RecallDeck
Направление

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

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

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

7 дней бесплатно на месяц или год · все функции включены.

Что внутри

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

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

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 гарантирует безопасность памяти без сборщика мусора?

Короткий ответ: Rust проверяет владение и заимствования статически, на этапе компиляции. Borrow checker доказывает, что каждая ссылка живёт не дольше своих данных и что нет одновременного алиасинга с мутацией — поэтому use-after-free, double-free и гонки данных отсекаются ещё до запуска. Никакого GC и подсчёта ссылок по умолчанию: платишь временем компиляции и порогом входа.

Подробно:

  1. Владение — у каждого значения ровно один владелец; когда он выходит из скоупа, память освобождается детерминированно (Drop), без пауз рантайма.
  2. Заимствование — компилятор следит за правилом «либо много &T, либо одна &mut T», что и убивает гонки данных статически.
  3. Лайфтаймы — borrow checker сопоставляет времена жизни ссылок и данных, не давая появиться висячей ссылке.
  4. Zero-cost abstractions — за безопасность платит компилятор, в бинарнике проверок нет.
Критерий Rust Языки с GC
Когда проверяется компиляция рантайм
Стоимость в рантайме нулевая паузы GC / refcount
Как проявляются ошибки ошибка компиляции утечки, задержки, редкие баги

⚠️ Частая ошибка: сказать «Rust считает ссылки, как ARC в Swift» или «под капотом есть GC». По умолчанию нет ни того, ни другого — Rc/Arc это опциональный инструмент, а не механизм безопасности памяти.

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

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

Подробно:

  1. Полиморфизм — общий интерфейс через trait + дефолтные методы; статически (дженерики) или динамически (dyn).
  2. Blanket implimpl<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-разработчик», полным планировщиком SM-2, статистикой, гибким темпом и блиц-режимом. Отменить можно онлайн до первого списания.

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