Vai al contenuto
eLearner.app
Modulo 7 · Lezione 2 di 214/14 nel corso~15 min
Lezioni del modulo (2/2)

Gestione errori e operatore ?

La filosofia di Rust incoraggia a riconoscere la possibilità di errori in modo esplicito e a strutturare il codice per gestirli prima che il programma venga compilato.

Gli errori in Rust si dividono in due categorie principali: errori irrecuperabili (che causano il blocco immediato tramite il panico panic!) ed errori recuperabili (gestiti tramite il tipo Result<T, E>).


Il tipo Result<T, E> ed il Pattern Matching

La maggior parte degli errori recuperabili restituisce un tipo Result<T, E> che è un'enum definita come:

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

Possiamo usare il pattern matching per ispezionare il risultato:

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),
    };
}

Propagazione degli Errori con l'operatore ?

Quando implementiamo una funzione, invece di gestire l'errore direttamente al suo interno, spesso vogliamo restituire l'errore al chiamante affinché sia lui a decidere cosa fare. Questo processo è chiamato propagazione degli errori.

Rust fornisce l'operatore ? come scorciatoia sintattica per propagare gli errori. Se il valore di un Result è Ok, il valore interno a Ok viene restituito dall'espressione; se è Err, l'errore Err viene restituito dall'intera funzione corrente come se avessimo usato un 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)
}

[!IMPORTANT] L'operatore ? può essere utilizzato solo in funzioni che restituiscono un tipo compatibile con il valore su cui viene applicato (generalmente Result, Option, o tipi che implementano FromResidual).


Errori Personalizzati

Possiamo definire i nostri tipi di errore personali implementando il trait std::fmt::Display (e opzionalmente std::error::Error) per fornire una rappresentazione leggibile dell'errore:

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 {}

Prova tu

Esercizio 1: Leggere un file con l'operatore ?

Esercizio#rust.m7.l2.e1
Tentativi: 0Caricamento…

Completa la funzione read_username_from_file in modo che utilizzi l'operatore ? per propagare gli errori generati dall'apertura del file e dalla lettura del suo contenuto nella stringa username.

Caricamento editor…
Mostra suggerimento

Aggiungi il carattere `?`dopo`File::open(...)`e dopo`username_file.read_to_string(...)` per propagare gli errori.

Soluzione disponibile dopo 3 tentativi

Esercizio 2: Analizzare ed elaborare un numero

Esercizio#rust.m7.l2.e2
Tentativi: 0Caricamento…

Scrivi una funzione chiamata parse_and_double che accetta in input un riferimento a stringa &str e restituisce un Result<i32, std::num::ParseIntError>. La funzione deve analizzare la stringa con val.parse::<i32>() usando ? per propagare l'errore di parsing, e in caso di successo restituire il valore raddoppiato racchiuso in Ok.

Caricamento editor…
Mostra suggerimento

Usa `val.parse::<i32>()?`per convertire la stringa propagando l'errore, poi restituisci`Ok(num \* 2)`.

Soluzione disponibile dopo 3 tentativi

Esercizio 3: Definire un errore personalizzato

Esercizio#rust.m7.l2.e3
Tentativi: 0Caricamento…

Definisci una struttura vuota chiamata CustomError. Implementa il trait std::fmt::Display per essa scrivendo all'interno del metodo fmt il messaggio 'Si e verificato un errore personalizzato'.

Caricamento editor…
Mostra suggerimento

Dichiara `struct CustomError;`ed implementa Display scrivendo`write!(f, "Si e verificato un errore personalizzato")`nel metodo`fmt`.

Soluzione disponibile dopo 3 tentativi