Перейти до основного вмісту
Модуль 7 · Урок 2 із 214/14 у курсі~15 min
Модульні уроки (2/2)

Обробка помилок і ? Оператор

Філософія Rust заохочує вас чітко розпізнавати можливість помилок і структурувати свій код для їх обробки до компіляції програми.

Помилки в Rust поділяються на дві основні категорії: невиправні помилки (які викликають негайне припинення через макрос panic!) і виправні помилки (керовані за допомогою типу Result<T, E>).


Тип результату<T, E> і відповідність шаблону

Більшість помилок, які можна виправити, повертають тип Result<T, E>, який є переліком, визначеним як:

Rust
enum Result<T, E> {
    Ok(T),
    Err(E),
}

Ми можемо використовувати зіставлення за зразком, щоб перевірити результат:

Rust
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(...).

Rust
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), щоб забезпечити зрозуміле для людини представлення помилки:

Rust
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: Читання файлу за допомогою ? оператор

вправи#rust.m7.l2.e1
Спроби: 0Завантаження…

Завершіть функцію read_username_from_file, щоб вона використовувала ? оператор для розповсюдження помилок, створених під час відкриття файлу та читання його вмісту в рядку імені користувача.

Завантаження редактора…
Показати підказку

Додайте символ «?» після «File::open(...)» і після «username_file.read_to_string(...)», щоб поширювати помилки.

Рішення доступне після 3 спроб

Вправа 2: Синтаксичний розбір і подвоєння числа

вправи#rust.m7.l2.e2
Спроби: 0Завантаження…

Напишіть функцію під назвою parse_and_double, яка приймає посилання на рядок &str і повертає результат<i32, std::num::ParseIntError>. Функція має аналізувати рядок за допомогою val.parse::<i32>() із ? для розповсюдження помилок аналізу та в разі успіху повертає подвоєне значення, загорнуте в Ok.

Завантаження редактора…
Показати підказку

Використовуйте `val.parse::<i32>()?`, щоб проаналізувати рядок і поширити помилку, а потім поверніть `Ok(num \* 2)`.

Рішення доступне після 3 спроб

Вправа 3: визначення власної помилки

вправи#rust.m7.l2.e3
Спроби: 0Завантаження…

Визначте порожню структуру під назвою CustomError. Реалізуйте властивість std::fmt::Display для нього, написавши «Si e verificato un errore personalizzato» як повідомлення про помилку в методі fmt.

Завантаження редактора…
Показати підказку

Оголошіть `struct CustomError;`і реалізуйте Display, написавши`write!(f, "Si e verificato un errore personalizzato")`всередині методу `fmt`.

Рішення доступне після 3 спроб