сеньорчикОткрыть в Telegram
← все вопросывопросы для собеседований · Экосистема Rust

Вопросы по экосистеме Rust на собеседовании

Язык языком, а работать придётся с Cargo, serde и чужими крейтами, поэтому прикладной блок спрашивают почти всегда. Проверяют бытовую зрелость: понимаешь ли, как фичи складываются между зависимостями, где живут тесты и почему в проде фиксируют тулчейн.

75 вопросов в банке·6 подтем·ниже разбор 9

Что спрашивают

Из чего состоит тема

Так тема разложена в тренажёре: движок ведёт прогресс по каждой подтеме отдельно и возвращает те, где вы ошибаетесь.

Разборы подтем

Конспект по каждой: что это, как отвечать вслух, на чём валятся, плюс вопросы для самопроверки.

Примеры вопросов с разбором

  1. #rs_cargo1 / 9
    Зачем нужен Cargo.lock, если версии уже указаны в Cargo.toml?
    A)Он хранит контрольные суммы исходников для проверки лицензий
    B)Он фиксирует точные версии всего дерева зависимостей
    C)Он задаёт порядок сборки зависимостей в рабочем пространстве
    D)Он кэширует скачанные крейты для сборки без сети
    показать ответ и разбор
    +B)Он фиксирует точные версии всего дерева зависимостей

    // разбор: В Cargo.toml обычно стоит диапазон вроде "1.0", а lock записывает, какая именно версия каждого крейта была выбрана — включая транзитивные. Благодаря этому сборка воспроизводима у всех и в CI. Для приложений lock коммитят в репозиторий, для библиотек он на пользователей не влияет.

  2. #rs_macros2 / 9
    Чем macro_rules! отличается от процедурного макроса?
    A)Первый сопоставляет образцы, второй — код над токенами
    B)Первый умеет генерировать типы, второй — только выражения
    C)Первый работает в рантайме, второй — на этапе компиляции
    D)Первый доступен только внутри своего модуля, второй — публичный
    показать ответ и разбор
    +A)Первый сопоставляет образцы, второй — код над токенами

    // разбор: macro_rules! — это набор правил «такой образец превращается в такой код», декларативно и без отдельного крейта. Процедурный макрос — программа, которая получает поток токенов и возвращает новый: так работают derive, атрибуты вроде tokio::main и функциональные макросы. Оба разворачиваются при компиляции, но второй мощнее и заметно дороже по времени сборки.

  3. #rs_serde3 / 9
    Что делает #[derive(Serialize, Deserialize)] из serde?
    A)Генерирует обход полей структуры для любого формата
    B)Регистрирует структуру в глобальном реестре типов serde
    C)Превращает структуру в JSON при каждом присваивании
    D)Добавляет к структуре методы to_json и from_json
    показать ответ и разбор
    +A)Генерирует обход полей структуры для любого формата

    // разбор: serde разделяет модель данных и формат: derive пишет обход полей, а конкретный формат подключается отдельным крейтом — serde_json, bincode, serde_yaml. Поэтому одна структура сериализуется куда угодно без изменений, а работа с полями раскрывается в прямой код без рефлексии и без обхода по именам в рантайме.

  4. #rs_testing4 / 9
    Чем юнит-тесты в модуле отличаются от тестов в каталоге tests/?
    A)Модульные запускаются командой cargo test, а тесты в tests/ — отдельной командой
    B)Тесты в tests/ выполняются последовательно, модульные — параллельно
    C)Модульные видят приватные элементы, тесты в tests/ — только публичный API
    D)Модульные попадают в релизный бинарник, тесты в tests/ — нет
    показать ответ и разбор
    +C)Модульные видят приватные элементы, тесты в tests/ — только публичный API

    // разбор: Модуль tests лежит внутри крейта, поэтому видит внутренности через use super::*. Каталог tests/ компилируется как отдельные крейты и работает с библиотекой снаружи — ровно как её будущий пользователь. Обе категории гоняет один cargo test, и обе не попадают в релизную сборку.

  5. #rs_tooling5 / 9
    Чем занимается clippy?
    A)Форматирует код по единому стилю
    B)Проверяет зависимости на известные уязвимости
    C)Ищет неидиоматичные места сверх проверок компилятора
    D)Ищет неопределённое поведение в unsafe-коде
    показать ответ и разбор
    +C)Ищет неидиоматичные места сверх проверок компилятора

    // разбор: Это линтер с сотнями правил: лишний clone, ручной цикл вместо итератора, unwrap там, где просится разбор, подозрительные сравнения. Часть подсказок применяется автоматически через --fix. Форматированием занимается rustfmt, уязвимостями — cargo audit, а неопределённым поведением — Miri: инструменты разные.

  6. #rs_web_db6 / 9
    Чем sqlx отличается от diesel по подходу?
    A)sqlx синхронный, diesel асинхронный
    B)sqlx проверяет SQL при компиляции, diesel даёт типизированный DSL
    C)sqlx требует миграций, diesel создаёт схему автоматически
    D)sqlx работает только с PostgreSQL, diesel — со всеми базами
    показать ответ и разбор
    +B)sqlx проверяет SQL при компиляции, diesel даёт типизированный DSL

    // разбор: В sqlx пишут привычный SQL, а макрос query! сверяет его с реальной базой на этапе компиляции — нужен доступ к базе или сохранённые метаданные. Diesel вместо строк даёт типизированный конструктор запросов поверх схемы. Первый ближе тем, кто думает на SQL, второй ловит больше ошибок формой типов, но хуже переносит нестандартные запросы.

  7. #rs_cargo7 / 9
    Что означает запись зависимости serde = "1.2"?
    A)Ровно версию 1.2.0, без обновлений
    B)Последнюю доступную версию на момент сборки
    C)Версии от 1.2.0 до 2.0.0, без мажорного обновления
    D)Версии ветки 1.2.x: минорные обновления не подтянутся
    показать ответ и разбор
    +C)Версии от 1.2.0 до 2.0.0, без мажорного обновления

    // разбор: По умолчанию действует правило совместимости: строка равносильна ^1.2 — обновления в пределах мажорной версии считаются безопасными и подтягиваются, переход на 2.0 — нет. Точную версию задают через =1.2.0, а ветку — через ~1.2. Что именно выбрано, видно в lock-файле.

  8. #rs_macros8 / 9
    Что означает гигиена макросов в Rust?
    A)Компилятор проверяет макрос на бесконечную рекурсию
    B)Макрос не может изменять код за пределами своего вызова
    C)Раскрытие макроса не зависит от порядка объявлений в файле
    D)Переменные макроса не конфликтуют с местом вызова
    показать ответ и разбор
    +D)Переменные макроса не конфликтуют с местом вызова

    // разбор: Идентификаторы, введённые внутри макроса, живут в своей области: объявленный там let x не затрёт x у вызывающего и не будет им подменён. В C такие коллизии — классическая ловушка препроцессора, здесь их нет. Гигиена частичная: типы и функции по именам всё-таки резолвятся в контексте вызова, поэтому в макросах пишут полные пути.

  9. #rs_serde9 / 9
    В JSON поле называется user_name, в структуре хочется userName. Что взять?
    A)Переименовать поле в структуре: serde сопоставляет только по именам
    B)Реализовать Deserialize вручную для этой структуры
    C)Добавить промежуточную структуру и конвертировать вручную
    D)Атрибут #[serde(rename_all = "camelCase")] или rename на поле
    показать ответ и разбор
    +D)Атрибут #[serde(rename_all = "camelCase")] или rename на поле

    // разбор: Атрибуты закрывают почти все расхождения между внешним форматом и внутренней моделью: rename и rename_all для имён, default для отсутствующих полей, skip_serializing_if для пустых, flatten для вложенности, with для своих преобразований. Ручная реализация нужна лишь в сложных случаях вроде разбора нестандартного формата даты.

это 9 из 75

Ещё 66 вопросов по теме — в тренажёре, с движком повторения

Прочитать разбор и ответить самому — разные навыки. В Сеньорчике вопросы идут сессиями, а движок возвращает подтемы, где вы ошибаетесь, пока они не начнут отскакивать. Бесплатно, лимит по энергии.

Частые вопросы