Result и оператор ?
Result делает ошибки видимыми в типе; оператор ? позволяет элегантно их пробрасывать.
Result<T, E> — тип результата операции, которая может не удаться:
Ok(значение)при успехе илиErr(ошибка)при сбое.
Ошибки как значения
В Rust нет исключений. Операция, которая может провалиться, возвращает Result<T, E> — ещё одно перечисление стандартной библиотеки. Ошибка становится обычным значением, которое нельзя случайно проигнорировать.
// так Result определён в стандартной библиотеке
enum Result<T, E> {
Ok(T), // успех, внутри результат
Err(E), // ошибка, внутри её причина
}Поскольку результат «завёрнут», вы обязаны разобрать его, прежде чем добраться до значения, — а значит, обязаны учесть возможность сбоя.
fn parse_age(s: &str) -> Result<u32, std::num::ParseIntError> {
s.parse::<u32>() // parse возвращает Result
}
fn main() {
match parse_age("30") {
Ok(age) => println!("возраст: {age}"),
Err(e) => println!("ошибка: {e}"),
}
match parse_age("abc") {
Ok(age) => println!("возраст: {age}"),
Err(e) => println!("ошибка: {e}"),
}
}Вывод:
возраст: 30 ошибка: invalid digit found in string
Оператор ? — пробрасывание ошибок
Писать match на каждый Result утомительно, особенно когда операций несколько подряд. Для этого есть оператор ?: он разворачивает Ok и продолжает, а при Err немедленно возвращает эту ошибку из функции. По сути это «дай значение или верни ошибку наверх».
fn sum_two(a: &str, b: &str) -> Result<i32, std::num::ParseIntError> {
let x = a.parse::<i32>()?; // если Err — выходим из функции с этой ошибкой
let y = b.parse::<i32>()?;
Ok(x + y)
}
fn main() {
println!("{:?}", sum_two("10", "20")); // Ok(30)
println!("{:?}", sum_two("10", "xx")); // Err(...)
}Вывод:
Ok(30)
Err(ParseIntError { kind: InvalidDigit })Без ? тот же код потребовал бы двух вложенных match. Оператор ? работает в функциях, которые сами возвращают Result (или Option), и делает «счастливый путь» линейным и читаемым.
Полезные методы Result
| Метод | Что делает |
.is_ok() / .is_err() | проверить исход без распаковки |
.unwrap() | достать Ok или паника при Err |
.unwrap_or(d) | значение из Ok или запасное d |
.ok() | превратить в Option (ошибку отбросить) |
unwrap() удобен для быстрых прототипов и примеров, но в надёжном коде его избегают: он превращает ошибку в панику. Лучше обработать Err явно или пробросить через ?.
Итог
- Ошибки в Rust — это значения:
Result<T, E>с вариантамиOkиErr. - Оператор
?разворачиваетOkили возвращаетErrнаверх, делая код линейным. ?работает в функциях, возвращающихResultилиOption.