Направление

Подготовка к собеседованию — Rust-разработчик

Колода из 136+ карточек с вопросами для собеседования по направлению «Rust-разработчик» — по темам и уровню сложности, с повторениями по вашим оценкам. Посмотрите несколько карточек ниже, затем выберите доступ, чтобы учить всё направление по расписанию в стиле Anki (SM-2).

136 карточек10 тем
Посмотреть цены и начать

Новым подписчикам месяца или года может быть доступно 7 дней бесплатно. Условия и сумму подтвердит страница оплаты.

С чего начать

Перед темами владения и заимствования нужно освоить базовый синтаксис Rust. За модулями Rust идут общие вопросы по проектированию систем и поведенческому интервью; проверяйте примеры кода в небольшом проекте на Rust.

Первый проход: Владение, заимствование и лайфтаймы → Трейты, дженерики и диспетчеризация. Начните с базовых вопросов в этих модулях, затем продолжайте по плану. К сложным и senior-вопросам возвращайтесь по требованиям вакансии; все карточки доступны с самого начала.

Общие темы могут входить в несколько направлений и сохраняют одну историю повторений. План ниже отмечает общие основы и профильные модули; выбирайте глубину под свою вакансию.

Что внутри

Все темы направления, сгруппированные так, как вы будете их учить.

Владение, заимствование и лайфтаймы

12 карточек

Профильный модуль

Владение и лайфтаймы

Трейты, дженерики и диспетчеризация

11 карточек

Профильный модуль

Трейты и диспетчеризация

Умные указатели и interior mutability

7 карточек

Профильный модуль

Умные указатели

Ошибки, коллекции и экосистема

10 карточек

Профильный модуль

Ошибки и экосистема

Конкурентность: Send/Sync и атомики

8 карточек

Профильный модуль

Send/Sync и атомики

Async/await и Tokio

10 карточек

Профильный модуль

Async и Tokio

Unsafe, память и FFI

7 карточек

Профильный модуль

Unsafe и память

Live coding и прикладные задачи

7 карточек

Профильный модуль

Live coding

Системный дизайн

29 карточек

Общие основы

Системный дизайн

Поведенческое интервью

35 карточек

Общие основы

Поведенческое интервью

Примеры вопросов

Несколько карточек из колоды — откройте ответ, затем выберите доступ, чтобы учить весь набор по расписанию.

Как Rust гарантирует безопасность памяти без сборщика мусора?

Короткий ответ: Safe Rust сочетает владение, заимствования и проверку типов, предотвращая ошибки памяти без обязательного трассирующего сборщика мусора. Большинство правил ссылок проверяется при компиляции, но часть механизмов безопасности работает в рантайме.

Подробно:

  1. Владение определяет уничтожение значений. Drop может выполнять произвольную очистку: детерминированное уничтожение не означает бесплатную работу без задержек.
  2. Разделяемые ссылки обычно разрешают чтение, эксклюзивные — изменение. Типы с interior mutability дают контролируемые исключения с сохранением безопасности.
  3. Лайфтаймы ограничивают ссылки так, чтобы они не пережили объекты, на которые указывают.
  4. Проверки границ могут выполняться в рантайме; RefCell динамически проверяет заимствования, а Rc/Arc ведут счётчики ссылок. Затраты зависят от выбранных типов и операций.
  5. Код unsafe/FFI обязан вручную соблюдать инварианты безопасности. Safe-код полагается на корректность этих реализаций. Rust не гарантирует отсутствие утечек, deadlock или всех логических ошибок.

Важно: «Нет обязательного трассирующего GC» — верно. «Вся безопасность бесплатна и проверок в рантайме нет» — неверно.

Источники: Interior mutability Rust, unsafe Rust.

В Rust нет наследования классов — чем трейты и композиция заменяют классическое ООП?

Короткий ответ: Трейты дают полиморфизм в стиле интерфейсов — с методами по умолчанию и blanket-реализациями. Супертрейт — это обязательство «реализуй ещё и тот трейт», а не наследование полей и поведения. Переиспользование кода в Rust строится на композиции: вкладываешь тип в структуру и делегируешь (в т. ч. через Deref).

Подробно:

  1. Полиморфизм — общий интерфейс через trait + дефолтные методы; статически (дженерики) или динамически (dyn).
  2. Blanket impl — impl<T: Display> ToString for T даёт ToString сразу всем Display-типам — переиспользование без иерархии.
  3. Супертрейт ≠ наследование — trait B: A требует реализовать и A, но не наследует его состояние; это ограничение, а не «is-a».
  4. Композиция — поля-компоненты + делегирование методов заменяют цепочки классов; «has-a» вместо «is-a».
ООП-концепция Аналог в Rust
интерфейс trait
абстрактный метод метод трейта без тела
метод по умолчанию дефолтный метод трейта
наследование поведения композиция + делегирование
наследование интерфейса супертрейт (trait B: A)

⚠️ Частая ошибка: называть супертрейт «наследованием». Он не тянет за собой поля и реализацию — это лишь требование реализовать другой трейт.

Когда выбирать Box, Rc и Arc? Чем они отличаются?

Короткий ответ: Box<T> — единоличный владелец, обычная аллокация в куче с нулевой стоимостью разыменования. Rc<T> — разделяемое владение через неатомарный счётчик ссылок, только внутри одного потока. Arc<T> — то же разделяемое владение, но счётчик обновляется атомарно, поэтому его можно шарить между потоками (ценой атомарных операций).

Подробно:

  1. Box<T> — один владелец, счётчика нет. Нужен, когда значение должно лежать в куче: рекурсивные структуры, трейт-объекты (Box<dyn Trait>), большие значения. Разыменование бесплатно.
  2. Rc<T> — несколько владельцев в одном потоке. clone() инкрементит strong-счётчик, drop декрементит; данные освобождаются при достижении нуля. Отдаёт только &T — для мутации кладут RefCell внутрь.
  3. Arc<T> — как Rc, но счётчик на атомиках (fetch_add/fetch_sub). Реализует Send/Sync, годится для многопоточки; для мутации оборачивают в Mutex/RwLock.
Владельцев Потоков Тип
один — Box<T>
много один Rc<T>
много несколько Arc<T>

⚠️ Частая ошибка: тянуть Arc везде «на всякий случай». Если владелец один — хватит Box или вообще стека; атомарные операции Arc не бесплатны, а в одном потоке это чистые накладные расходы.

Когда использовать Option, а когда Result<T, E>?

Короткий ответ: Option<T> — когда значение может просто отсутствовать и причина неважна (Some/None). Result<T, E> — когда операция может завершиться ошибкой и вызывающему нужна причина сбоя (Ok/Err).

Подробно:

  1. Option — моделирует «значения может не быть»: HashMap::get не нашёл ключ, Vec::first на пустом векторе. None не несёт информации о причине.
  2. Result — моделирует «операция провалилась»: File::open не нашёл файл, str::parse не смог распарсить. Err(e) объясняет, что пошло не так.
  3. Конвертация — они легко переходят друг в друга: option.ok_or(err) превращает None в Err, а result.ok() отбрасывает ошибку и даёт Option.
Тип Смысл Типичный API
Option значение может отсутствовать HashMap::get, Vec::first
Result<T, E> операция может провалиться File::open, str::parse

⚠️ Частая ошибка: возвращать Result там, где отсутствие — норма (или Option там, где нужна причина сбоя). «Ключа нет» — это Option, а не ошибка.

Что такое Send и Sync и как компилятор выводит их автоматически?

Короткий ответ: Send означает, что владение значением можно безопасно передать в другой поток; Sync — что &T можно безопасно шарить между потоками (по определению T: Sync ⇔ &T: Send). Это авто-трейты (auto traits): компилятор реализует их структурно — тип Send/Sync, если все его поля Send/Sync. Ничего писать руками не надо.

Подробно:

  1. Структурный вывод — авто-трейт распространяется по полям: структура из Send-полей сама Send. Сырые указатели (*const T, *mut T) осознанно отказываются от обоих трейтов, из-за чего типы поверх них тоже теряют их.
  2. unsafe impl — если ты гарантируешь потокобезопасность вручную (например, обернул сырой указатель в корректную синхронизацию), можно unsafe impl Send for MyType {}. Это утверждение под твою ответственность: компилятор проверить его не может.
  3. Явный отказ — negative impl (impl !Send for T) доступен только на nightly; так Rc помечен внутри std. На stable трейт снимают маркерным полем вроде PhantomData<*const ()> (!Send + !Sync).
Тип Send Sync Почему
Rc<T> нет нет неатомарный счётчик ссылок
Arc<T> да да атомарный счётчик (при T: Send + Sync)
Cell<T> / RefCell<T> да нет несинхронизированная внутренняя мутабельность
Mutex<T> да да синхронизация внутри (при T: Send)
*mut T нет нет нет гарантий у сырого указателя

⚠️ Частая ошибка: думать, что Send и Sync — про «многопоточность типа вообще». Send — про перемещение владения между потоками, Sync — про разделяемый доступ по ссылке; это разные гарантии, и тип может иметь одну без другой.

Что такое Future и почему вызов async fn без .await ничего не запускает?

Короткий ответ: Future — это ленивая стейт-машина, реализующая трейт Future с методом poll. Вызов async fn не запускает работу, а лишь конструирует объект футуры. Код внутри начинает выполняться, только когда футуру опрашивает (poll) исполнитель — то есть когда вы её .await-ите или отдаёте в spawn.

Подробно:

  1. async fn возвращает значение — тип impl Future<Output = T>. Сам вызов — это конструктор стейт-машины, а не старт вычисления.
  2. Ленивость — в отличие от потока, футура не крутится в фоне сама по себе. Пока её никто не poll-ит, она инертна.
  3. Кто двигает футуру — .await внутри другой async-функции или tokio::spawn, который отдаёт задачу рантайму. Без этого работа не начнётся.
async fn work() { println!("побежали"); }

let fut = work(); // ничего не произошло — печати нет
fut.await;        // вот теперь тело реально выполнилось

⚠️ Частая ошибка: ждать, что async fn стартует «как поток» сразу при вызове. Забытый .await — это не запущенная работа, а нередко и предупреждение unused_must_use: «futures do nothing unless you .await or poll them».

Готовы лучше запоминать?

Посмотрите пример, выберите направление и настройте регулярную практику под свою подготовку.

Вопросы об этом направлении

Как готовиться к собеседованию на «Rust-разработчик»?

Учите концепции, которые придётся объяснять, а не только те, что умеете кодить. Направление «Rust-разработчик» в RecallDeck даёт 136+ отобранных вопросов и возвращает каждый по расписанию в стиле Anki (SM-2), основанному на ваших оценках — чтобы тренировать вспоминание и объяснение. Дополняйте повторения кодингом и пробными собеседованиями.

Какие темы охватывает направление «Rust-разработчик»?

Направление «Rust-разработчик» разбито на ключевые области, которые реально проверяют на таких собеседованиях, — по темам и уровню сложности (Concept, Junior, Middle, Senior). Полный план и примеры вопросов можно посмотреть выше до входа.

Помогает ли интервальное повторение в подготовке к «Rust-разработчик»?

Да. Активное вспоминание и честная самооценка помогают закреплять знания. RecallDeck назначает повторения карт по направлению «Rust-разработчик» на основе ваших оценок: знакомые карты возвращаются реже, а сложные получают больше практики.

Можно попробовать направление «Rust-разработчик» до оплаты?

Новым подписчикам месячного или годового тарифа может быть доступен пробный период семь дней со всем направлением «Rust-разработчик» и всеми функциями. Право на него и сумму подтвердит страница оплаты; при повторной подписке списание может быть сразу. Отмените подписку онлайн до конца пробного периода, чтобы избежать первого списания. У вечного доступа пробного периода нет.

Другие направления