Обработка ошибок в Rust
Обработка ошибок в Rust
Основные принципы обработки ошибок в Rust
-
Ошибки — это значения.
Функции, которые могут завершиться неудачей, возвращают типResult<T, E>, где:T— тип успешного результата,E— тип ошибки.
-
Нет
try/catch,throw,raise.
Обработка ошибок происходит явно через сопоставление с образцом (match), макросы (?), или комбинаторы (map,and_thenи т.д.). -
Паника (
panic!) существует, но предназначена только для необратимых ошибок (например, нарушение инвариантов, ошибки в логике программы).- Вызывает разворачивание стека (unwinding) или немедленное завершение (
abort). - Не должна использоваться для обработки ожидаемых ошибок (например, отсутствие файла, недопустимый ввод).
- Вызывает разворачивание стека (unwinding) или немедленное завершение (
Типы ошибок в Rust
Rust не определяет глобальную иерархию ошибок. Вместо этого используются конкретные типы, реализующие трейт std::error::Error.
1. Стандартные типы ошибок из std
-
std::io::Error— ошибки ввода-вывода:- Возникают при работе с файлами, сетью, процессами.
- Содержит код ошибки (
std::io::ErrorKind), например:NotFoundPermissionDeniedConnectionRefusedInvalidInputTimedOut- и др.
-
std::fmt::Error— ошибка при форматировании (например, в пользовательскомDisplay::fmt). -
std::num::ParseIntError,std::num::ParseFloatError— ошибки при парсинге чисел. -
std::str::Utf8Error— ошибка при проверке UTF-8. -
std::string::FromUtf8Error— ошибка при созданииStringиз байтов. -
std::env::VarError— ошибка при чтении переменной окружения:NotPresentNotUnicode
-
std::ffi::FromBytesWithNulError,std::ffi::NulError— ошибки при работе с C-совместимыми строками. -
std::path::StripPrefixError— ошибка при удалении префикса пути.
2. Трейт std::error::Error
Любой пользовательский тип ошибки должен реализовывать этот трейт (обычно автоматически через thiserror или вручную). Он требует:
Display::fmt— человекочитаемое сообщение,Debug::fmt— техническое представление,- опционально:
source()— ссылка на вложенную ошибку (цепочка причин).
3. Паники (не ошибки в обычном смысле)
Следующие ситуации вызывают panic!:
- Выход за границы массива:
index out of bounds - Деление на ноль
- Нарушение
assert!илиunwrap()наErr/None - Некорректная работа с
unsafe(например, двойное освобождение памяти)
Эти события не являются типами ошибок, а приводят к аварийному завершению потока.
Экосистемные практики
- Библиотеки определяют собственные типы ошибок, часто с помощью крейта
thiserror(для удобного определения) илиanyhow(для упрощённой обработки в приложениях). - Цепочки ошибок строятся через поле
source, а не через наследование. - Нет общего корневого типа ошибок, кроме как через динамическую диспетчеризацию (
Box<dyn std::error::Error>).
Примеры
use std::fs;
use std::num::ParseIntError;
fn read_number_from_file(path: &str) -> Result<i32, Box<dyn std::error::Error>> {
let contents = fs::read_to_string(path)?; // io::Error
let number: i32 = contents.trim().parse()?; // ParseIntError
Ok(number)
}
Здесь возможны две конкретные ошибки: std::io::Error и ParseIntError. Обе реализуют std::error::Error и могут быть упакованы в Box<dyn Error>.
Нет типов ошибок
В Rust нет единого списка «типов ошибок», аналогичного другим языкам, потому что:
- Ошибки представлены конкретными типами, а не иерархией классов.
- Нет встроенных исключений вроде
IndexError,KeyError. - Стандартная библиотека предоставляет набор специализированных типов ошибок для разных подсистем.
- Пользовательские ошибки определяются явно и композиционно.
Таким образом, вместо таксономии исключений Rust предлагает типобезопасную, композиционную модель обработки ошибок через Result и трейт Error.
См. также
Другие статьи этого же раздела в боковом меню (как на странице «О разделе»). Инициатором проекта стал Graydon Hoare, тогда — независимый исследователь и разработчик, работавший в Mozilla с 2006 года. До этого он участвовал в разработке компиляторов и языковых инструментов,… Фундамент для начинающего программиста - что повторить, как работать, чего ожидать. Набор советов, правил, принципов и обычаев в разработке на этом языке. Черты могут иметь методы по умолчанию. Если тип не переопределяет метод, используется версия из черты. Это позволяет расширять функциональность без изменения базового кода. fn - ключевое слово, которое обозначает начало объявления функции. Функция представляет собой именованный блок кода, выполняющий конкретную задачу. В данном случае функция называется main. Rust — это язык системного программирования, сочетающий безопасность памяти, высокую производительность и выразительность. Его экосистема охватывает широкий спектр областей — от встраиваемых систем… Системное программирование — это разработка программного обеспечения, отвечающего за взаимодействие с аппаратной частью компьютера и операционной системой. Такое ПО создаёт фундамент, на котором… Кавычки, точки, запятые, скобки и прочие знаки препинания. Ключевое слово Значение -------------------------- abstract Зарезервировано для будущих версий языка become Зарезервировано для будущих версий языка box Зарезервировано для будущих версий языка do… Макрос / Атрибут Назначение ------------------------------ test Пометка функции как теста для cargo test should_panic Ожидание паники при выполнении теста ignore Пропуск теста при обычном запуске… Типизация, набор правил определения типа данных значений языка. Циклы в Rust — это конструкции, предназначенные для многократного выполнения блока кода до тех пор, пока выполняется определённое условие или не исчерпан набор данных. В отличие от многих других…История языка Rust
Что требуется знать перед началом изучения языка программирования Rust
Рекомендации по разработке на Rust
Rust для начинающих
Основы языка Rust
Экосистема приложений на Rust
Системное программирование на Rust
Синтаксис и пунктуация в Rust
Ключевые слова языка Rust
Встроенные функции и стандартная библиотека
Типы данных и владение памятью
Управляющие конструкции и циклы в Rust