Przejdź do głównej treści
eLearner.app
Moduł 7 · Lekcja 2 z 214/14 w kursie~15 min
Lekcje modułu (2/2)

Obsługa błędów i operator ?

Filozofia Rusta zachęca do jawnego rozpoznawania możliwości wystąpienia błędów i konstruowania kodu tak, aby obsługiwał je przed skompilowaniem programu.

Błędy w Rust są podzielone na dwie główne kategorie: błędy nienaprawialne (powodujące natychmiastowe zawieszenie poprzez panikę panic!) i błędy naprawialne (obsługiwane przez typ Result<T, E>).


Typ wyniku<T, E> i dopasowanie wzorca

Większość możliwych do naprawienia błędów zwraca typ Result<T, E>, który jest wyliczeniem zdefiniowanym jako:

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

Możemy użyć dopasowywania wzorców, aby sprawdzić wynik:

Code
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!("Problema nell'aprire il file: {:?}", error),
    };
}

Propagacja błędów za pomocą operatora ?

Kiedy implementujemy funkcję, zamiast bezpośrednio w niej obsługiwać błąd, często chcemy zwrócić błąd osobie wywołującej, aby mógł zdecydować, co zrobić. Proces ten nazywany jest propagacją błędów.

Rust udostępnia operator ? jako skrót składniowy do propagacji błędów. Jeśli wartość Result wynosi Ok, wartość w obrębie Ok jest zwracana przez wyrażenie; jeśli jest to Err, cała bieżąca funkcja zwraca błąd Err, tak jakbyśmy użyli return Err(...).

Code
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)
}

[!WAŻNE] Operatora ? można używać tylko w funkcjach zwracających typ zgodny z wartością, do której jest zastosowany (zwykle Result, Option lub typy implementujące FromResidual).


Błędy niestandardowe

Możemy zdefiniować własne typy błędów, implementując cechę std::fmt::Display (i opcjonalnie std::error::Error), aby zapewnić czytelną dla człowieka reprezentację błędu:

Code
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, "Errore: {}", self.details)
    }
}

impl std::error::Error for MyError {}

Spróbuj sam

Ćwiczenie 1: Odczyt pliku z ? operator

Ćwiczenie#rust.m7.l2.e1
Próby: 0Ładowanie...

Wypełnij funkcję read_username_from_file, aby użyć ? operator. do propagowania błędów generowanych przez otwarcie pliku i wczytanie jego zawartości do ciągu nazwy użytkownika.

Ładowanie edytora...
Pokaż wskazówkę

Dodaj znak `?` po`File::open(...)`i po`username_file.read_to_string(...)`, aby propagować błędy.

Rozwiązanie dostępne po 3 próbach

Ćwiczenie 2: Analiza i przetwarzanie liczby

Ćwiczenie#rust.m7.l2.e2
Próby: 0Ładowanie...

Napisz funkcję o nazwie parse_and_double, która przyjmuje jako dane wejściowe odwołanie do ciągu znaków &str i zwraca Result<i32, std::num::ParseIntError>. Funkcja powinna przeanalizować ciąg za pomocą val.parse::<i32>() przy użyciu ? aby propagować błąd analizy i jeśli się powiedzie, zwróć podwojoną wartość ujętą w OK.

Ładowanie edytora...
Pokaż wskazówkę

Użyj `val.parse::<i32>()?`, aby przekonwertować ciąg poprzez propagację błędu, a następnie zwróć`Ok(num * 2)`.

Rozwiązanie dostępne po 3 próbach

Ćwiczenie 3: Zdefiniuj błąd niestandardowy

Ćwiczenie#rust.m7.l2.e3
Próby: 0Ładowanie...

Zdefiniuj pustą strukturę o nazwie CustomError. Zaimplementuj dla niego cechę std::fmt::Display, wpisując komunikat „Wystąpił błąd niestandardowy” wewnątrz metody fmt.

Ładowanie edytora...
Pokaż wskazówkę

Zadeklaruj `struct CustomError;` i zaimplementuj Display, wpisując `write!(f, "Si e verificato un errore personalizzato")`w metodzie`fmt`.

Rozwiązanie dostępne po 3 próbach