Модульні уроки (2/2)
Обробка помилок і ? Оператор
Філософія Rust заохочує вас чітко розпізнавати можливість помилок і структурувати свій код для їх обробки до компіляції програми.
Помилки в Rust поділяються на дві основні категорії: невиправні помилки (які викликають негайне припинення через макрос panic!) і виправні помилки (керовані за допомогою типу Result<T, E>).
Тип результату<T, E> і відповідність шаблону
Більшість помилок, які можна виправити, повертають тип Result<T, E>, який є переліком, визначеним як:
enum Result<T, E> {
Ok(T),
Err(E),
}Ми можемо використовувати зіставлення за зразком, щоб перевірити результат:
use std::fs::File;
fn main() {
let greeting_file_result = File::open("hello.txt");
let greeting_file = match greeting_file_result {
Ok(file) => file,
Err(error) => panic!("Problem opening the file: {:?}", error),
};
}Поширення помилки за допомогою оператора ?
Під час реалізації функції замість того, щоб обробляти помилку безпосередньо в ній, ми часто хочемо повернути помилку абоненту, щоб він міг вирішити, що робити. Цей процес називається розповсюдженням помилки.
Rust надає оператор ? як синтаксичний ярлик для поширення помилок. Якщо значення Result дорівнює Ok, вираз повертає внутрішнє значення Ok; якщо це Err, помилка Err повертається з усієї поточної функції, як якщо б ми використовували return Err(...).
use std::fs::File;
use std::io::{self, Read};
fn read_username_from_file() -> Result<String, io::Error> {
let mut username_file = File::open("username.txt")?;
let mut username = String::new();
username_file.read_to_string(&mut username)?;
Ok(username)
}[!ВАЖЛИВО] Оператор
?можна використовувати лише у функціях, які повертають тип, сумісний із значенням, до якого він застосований (зазвичайResult,Optionабо типи, що реалізуютьFromResidual).
Спеціальні помилки
Ми можемо визначити власні власні типи помилок, реалізувавши властивість std::fmt::Display (і, за бажанням, std::error::Error), щоб забезпечити зрозуміле для людини представлення помилки:
use std::fmt;
#[derive(Debug)]
struct MyError {
details: String,
}
impl fmt::Display for MyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Error: {}", self.details)
}
}
impl std::error::Error for MyError {}Спробуйте самі
Вправа 1: Читання файлу за допомогою ? оператор
Завершіть функцію read_username_from_file, щоб вона використовувала ? оператор для розповсюдження помилок, створених під час відкриття файлу та читання його вмісту в рядку імені користувача.
Показати підказку
Додайте символ «?» після «File::open(...)» і після «username_file.read_to_string(...)», щоб поширювати помилки.
Рішення доступне після 3 спроб
Вправа 2: Синтаксичний розбір і подвоєння числа
Напишіть функцію під назвою parse_and_double, яка приймає посилання на рядок &str і повертає результат<i32, std::num::ParseIntError>. Функція має аналізувати рядок за допомогою val.parse::<i32>() із ? для розповсюдження помилок аналізу та в разі успіху повертає подвоєне значення, загорнуте в Ok.
Показати підказку
Використовуйте `val.parse::<i32>()?`, щоб проаналізувати рядок і поширити помилку, а потім поверніть `Ok(num \* 2)`.
Рішення доступне після 3 спроб
Вправа 3: визначення власної помилки
Визначте порожню структуру під назвою CustomError. Реалізуйте властивість std::fmt::Display для нього, написавши «Si e verificato un errore personalizzato» як повідомлення про помилку в методі fmt.
Показати підказку
Оголошіть `struct CustomError;`і реалізуйте Display, написавши`write!(f, "Si e verificato un errore personalizzato")`всередині методу `fmt`.
Рішення доступне після 3 спроб