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

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

Исключений в языке нет, поэтому ошибка — обычное значение, и её обработка становится частью сигнатуры функции. Собес проверяет чувство границы: что считать багом и уронить паникой, а что вернуть вызывающему, и как при этом не превратить каждый вызов в лестницу из match.

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

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

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

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

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

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

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

  1. #rs_custom_errors1 / 9
    Что должен реализовать свой тип ошибки, чтобы вести себя как ошибка стандартной библиотеки?
    A)Debug и Display, а поверх них трейт std::error::Error
    B)Clone и PartialEq, чтобы ошибку можно было сравнивать
    C)Только Display: остальное компилятор добавит сам
    D)Serialize из serde для передачи по сети
    показать ответ и разбор
    +A)Debug и Display, а поверх них трейт std::error::Error

    // разбор: Трейт Error требует Debug и Display как супертрейты: первый нужен для {:?} и вывода из main, второй — для человекочитаемого сообщения. Сам Error добавляет source() — ссылку на нижележащую причину, из которой складывается цепочка. Всё остальное — по желанию задачи.

  2. #rs_error_libs2 / 9
    Как делят зоны ответственности thiserror и anyhow?
    A)thiserror — типы ошибок библиотеки, anyhow — ошибка приложения
    B)thiserror генерирует ошибки, anyhow их логирует
    C)thiserror — для синхронного кода, anyhow — для асинхронного
    D)thiserror для ошибок ввода-вывода, anyhow для остальных
    показать ответ и разбор
    +A)thiserror — типы ошибок библиотеки, anyhow — ошибка приложения

    // разбор: Библиотека обязана дать пользователю разбираемый тип: thiserror генерирует Display, Error и From по атрибутам над enum. Приложению чаще нужен один тип на всё с контекстом — это anyhow::Error, он поглощает любую ошибку и умеет добавлять пояснения. Обратный порядок неудобен: anyhow в публичном API лишает пользователя возможности разобрать причину.

  3. #rs_panic3 / 9
    Что делает unwrap() у Result::Err?
    A)Возвращает саму ошибку вызывающему коду
    B)Возвращает значение по умолчанию для типа результата
    C)Завершает весь процесс с кодом возврата ошибки
    D)Паникует и валит поток, печатая содержимое ошибки
    показать ответ и разбор
    +D)Паникует и валит поток, печатая содержимое ошибки

    // разбор: unwrap разворачивает Ok, а на Err паникует с сообщением called Result::unwrap() on an Err value и Debug-выводом ошибки. Паника валит текущий поток, а не процесс: в main это выглядит как падение программы, в рабочем потоке — как его смерть с ошибкой в join. Понятнее expect с описанием ожидания.

  4. #rs_question_op4 / 9
    Что делает оператор ? в конце выражения let s = read(path)?;
    A)Разворачивает значение, а при ошибке паникует, как unwrap
    B)Пробует выполнить выражение и подставляет значение по умолчанию при сбое
    C)Помечает выражение как способное вернуть ошибку, не меняя поток
    D)При Ok разворачивает значение, при Err выходит из функции с этой ошибкой
    показать ответ и разбор
    +D)При Ok разворачивает значение, при Err выходит из функции с этой ошибкой

    // разбор: Это ранний выход: Ok(v) даёт v, Err(e) немедленно возвращает Err(e) из текущей функции. Работает только там, где тип возврата это позволяет — Result, Option или другой тип с Try. Именно ? делает код с ошибками линейным: счастливый путь читается сверху вниз без лестницы match.

  5. #rs_result_option5 / 9
    Чем Result<T, E> отличается от Option<T> по смыслу?
    A)Result используют в библиотеках, Option — в приложениях
    B)Result проверяется компилятором, Option можно игнорировать молча
    C)Result несёт причину неудачи, Option — факт отсутствия
    D)Result работает с типами из std, Option — с пользовательскими
    показать ответ и разбор
    +C)Result несёт причину неудачи, Option — факт отсутствия

    // разбор: Option отвечает на вопрос «есть значение или нет» — пустой список, ключ не найден, поле не заполнено. Result отвечает «получилось или нет и почему» — диск не читается, строка не разбирается. Между ними ходят через ok_or (Option в Result) и ok (Result в Option).

  6. #rs_custom_errors6 / 9
    Зачем ошибки приложения собирают в один enum с вариантами вместо строк?
    A)Enum занимает меньше памяти, чем String с текстом ошибки
    B)Строку компилятор не примет как тип ошибки в Result
    C)Вызывающий разбирает вариант через match и реагирует по-разному
    D)Только enum можно преобразовать через оператор ?
    показать ответ и разбор
    +C)Вызывающий разбирает вариант через match и реагирует по-разному

    // разбор: Строка годится только для лога: по ней не решить, ретраить запрос или показать пользователю форму. Enum делает исходы частью типа — NotFound, Timeout, Invalid(field) разбираются match, а компилятор напоминает про новые варианты. Текст при этом никуда не девается, он живёт в Display.

  7. #rs_error_libs7 / 9
    Что даёт .context("чтение конфига") у anyhow?
    A)Помечает ошибку как некритичную и продолжает выполнение
    B)Заменяет текст ошибки на переданный
    C)Добавляет к ошибке слой описания, сохраняя исходную причину
    D)Отправляет ошибку в систему трассировки вместе со стеком
    показать ответ и разбор
    +C)Добавляет к ошибке слой описания, сохраняя исходную причину

    // разбор: context надстраивает цепочку: наверху человеческое «чтение конфига», ниже — исходная io-ошибка, ещё ниже её причина. В логе это печатается лесенкой Caused by, и по ней видно и что делали, и на чём споткнулись. Исходная ошибка при этом остаётся доступной для разбора.

  8. #rs_panic8 / 9
    Чем expect("нужен конфиг") отличается от unwrap() при ошибке?
    A)Возвращает переданную строку как значение вместо паники
    B)Печатает переданное сообщение вместе с содержимым ошибки
    C)Заменяет ошибку своим текстом и передаёт её наверх
    D)Паникует только в debug-сборке, в release просто пишет в лог
    показать ответ и разбор
    +B)Печатает переданное сообщение вместе с содержимым ошибки

    // разбор: Поведение то же самое — паника, отличается лишь сообщение: expect добавляет строку автора, unwrap оставляет стандартный текст. В сообщение пишут не «что-то пошло не так», а ожидание, которое нарушено: «конфиг должен быть прочитан на старте» — по такому тексту причину видно сразу из лога.

  9. #rs_question_op9 / 9
    Функция возвращает Result<i32, ParseIntError>, а внутри стоит ? на чтении файла. Что скажет компилятор?
    A)Соберёт: ? приводит ошибку к типу возврата функции
    B)E0277: ошибку ввода-вывода не преобразовать в ParseIntError
    C)Соберёт с предупреждением о потере исходного типа ошибки
    D)E0308: несовпадение типов в возвращаемом значении функции
    показать ответ и разбор
    +B)E0277: ошибку ввода-вывода не преобразовать в ParseIntError

    // разбор: Оператор ? делает конверсию через From: чтобы вернуть io::Error из функции с ParseIntError, нужна реализация From<io::Error> for ParseIntError — её нет и быть не может. Выходы: свой enum ошибок с From на оба случая, Box<dyn Error> или anyhow в прикладном коде.

это 9 из 60

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

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

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