Подготовка к собеседованию — Rust-разработчик
Колода из 136+ карточек с вопросами для собеседования по направлению «Rust-разработчик» — по темам и уровню сложности, с возвратом ровно перед тем, как вы забудете. Посмотрите несколько карточек ниже, затем выберите доступ, чтобы учить всё направление по расписанию в стиле Anki (SM-2).
7 дней бесплатно на месяц или год · все функции включены.
Что внутри
Все темы направления, сгруппированные так, как вы будете их учить.
Владение, заимствование и лайфтаймы
12 карточекТрейты, дженерики и диспетчеризация
11 карточекУмные указатели и interior mutability
7 карточекОшибки, коллекции и экосистема
10 карточекКонкурентность: Send/Sync и атомики
8 карточекAsync/await и Tokio
10 карточекUnsafe, память и FFI
7 карточекLive coding и прикладные задачи
7 карточекСистемный дизайн
29 карточекПоведенческое интервью
35 карточекПримеры вопросов
Несколько карточек из колоды — откройте ответ, затем выберите доступ, чтобы учить весь набор по расписанию.
Как Rust гарантирует безопасность памяти без сборщика мусора?
Как Rust гарантирует безопасность памяти без сборщика мусора?
Короткий ответ: Rust проверяет владение и заимствования статически, на этапе компиляции. Borrow checker доказывает, что каждая ссылка живёт не дольше своих данных и что нет одновременного алиасинга с мутацией — поэтому use-after-free, double-free и гонки данных отсекаются ещё до запуска. Никакого GC и подсчёта ссылок по умолчанию: платишь временем компиляции и порогом входа.
Подробно:
- Владение — у каждого значения ровно один владелец; когда он выходит из скоупа, память освобождается детерминированно (
Drop), без пауз рантайма. - Заимствование — компилятор следит за правилом «либо много
&T, либо одна&mut T», что и убивает гонки данных статически. - Лайфтаймы — borrow checker сопоставляет времена жизни ссылок и данных, не давая появиться висячей ссылке.
- Zero-cost abstractions — за безопасность платит компилятор, в бинарнике проверок нет.
| Критерий | Rust | Языки с GC |
|---|---|---|
| Когда проверяется | компиляция | рантайм |
| Стоимость в рантайме | нулевая | паузы GC / refcount |
| Как проявляются ошибки | ошибка компиляции | утечки, задержки, редкие баги |
⚠️ Частая ошибка: сказать «Rust считает ссылки, как ARC в Swift» или «под капотом есть GC». По умолчанию нет ни того, ни другого — Rc/Arc это опциональный инструмент, а не механизм безопасности памяти.
В Rust нет наследования классов — чем трейты и композиция заменяют классическое ООП?
В Rust нет наследования классов — чем трейты и композиция заменяют классическое ООП?
Короткий ответ: Трейты дают полиморфизм в стиле интерфейсов — с методами по умолчанию и blanket-реализациями. Супертрейт — это обязательство «реализуй ещё и тот трейт», а не наследование полей и поведения. Переиспользование кода в Rust строится на композиции: вкладываешь тип в структуру и делегируешь (в т. ч. через Deref).
Подробно:
- Полиморфизм — общий интерфейс через
trait+ дефолтные методы; статически (дженерики) или динамически (dyn). - Blanket impl —
impl<T: Display> ToString for TдаётToStringсразу всемDisplay-типам — переиспользование без иерархии. - Супертрейт ≠ наследование —
trait B: Aтребует реализовать иA, но не наследует его состояние; это ограничение, а не «is-a». - Композиция — поля-компоненты + делегирование методов заменяют цепочки классов; «has-a» вместо «is-a».
| ООП-концепция | Аналог в Rust |
|---|---|
| интерфейс | trait |
| абстрактный метод | метод трейта без тела |
| метод по умолчанию | дефолтный метод трейта |
| наследование поведения | композиция + делегирование |
| наследование интерфейса | супертрейт (trait B: A) |
⚠️ Частая ошибка: называть супертрейт «наследованием». Он не тянет за собой поля и реализацию — это лишь требование реализовать другой трейт.
Когда выбирать Box, Rc и Arc? Чем они отличаются?
Когда выбирать Box, Rc и Arc? Чем они отличаются?
Короткий ответ: Box<T> — единоличный владелец, обычная аллокация в куче с нулевой стоимостью разыменования. Rc<T> — разделяемое владение через неатомарный счётчик ссылок, только внутри одного потока. Arc<T> — то же разделяемое владение, но счётчик обновляется атомарно, поэтому его можно шарить между потоками (ценой атомарных операций).
Подробно:
Box<T>— один владелец, счётчика нет. Нужен, когда значение должно лежать в куче: рекурсивные структуры, трейт-объекты (Box<dyn Trait>), большие значения. Разыменование бесплатно.Rc<T>— несколько владельцев в одном потоке.clone()инкрементит strong-счётчик,dropдекрементит; данные освобождаются при достижении нуля. Отдаёт только&T— для мутации кладутRefCellвнутрь.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
Короткий ответ: Option<T> — когда значение может просто отсутствовать и причина неважна (Some/None). Result<T, E> — когда операция может завершиться ошибкой и вызывающему нужна причина сбоя (Ok/Err).
Подробно:
- Option — моделирует «значения может не быть»:
HashMap::getне нашёл ключ,Vec::firstна пустом векторе.Noneне несёт информации о причине. - Result — моделирует «операция провалилась»:
File::openне нашёл файл,str::parseне смог распарсить.Err(e)объясняет, что пошло не так. - Конвертация — они легко переходят друг в друга:
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 и как компилятор выводит их автоматически?
Короткий ответ: Send означает, что владение значением можно безопасно передать в другой поток; Sync — что &T можно безопасно шарить между потоками (по определению T: Sync ⇔ &T: Send). Это авто-трейты (auto traits): компилятор реализует их структурно — тип Send/Sync, если все его поля Send/Sync. Ничего писать руками не надо.
Подробно:
- Структурный вывод — авто-трейт распространяется по полям: структура из
Send-полей самаSend. Сырые указатели (*const T,*mut T) осознанно отказываются от обоих трейтов, из-за чего типы поверх них тоже теряют их. unsafe impl— если ты гарантируешь потокобезопасность вручную (например, обернул сырой указатель в корректную синхронизацию), можноunsafe impl Send for MyType {}. Это утверждение под твою ответственность: компилятор проверить его не может.- Явный отказ — 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 и почему вызов async fn без .await ничего не запускает?
Короткий ответ: Future — это ленивая стейт-машина, реализующая трейт Future с методом poll. Вызов async fn не запускает работу, а лишь конструирует объект футуры. Код внутри начинает выполняться, только когда футуру опрашивает (poll) исполнитель — то есть когда вы её .await-ите или отдаёте в spawn.
Подробно:
async fnвозвращает значение — типimpl Future<Output = T>. Сам вызов — это конструктор стейт-машины, а не старт вычисления.- Ленивость — в отличие от потока, футура не крутится в фоне сама по себе. Пока её никто не poll-ит, она инертна.
- Кто двигает футуру —
.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, статистикой, гибким темпом и блиц-режимом. Отменить можно онлайн до первого списания.