L'uso del tipo Result è diventato uno dei principali approcci alla gestione degli errori in Rust. Storicamente, in molti linguaggi, ad esempio C, gli errori venivano spesso segnalati tramite valori di ritorno speciali o variabili globali, il che portava a errori frequenti dovuti all'ignoranza di questi segnali. Rust ha optato per una tipizzazione esplicita degli errori tramite l'enumerazione Result<T, E>, rendendo impossibile l'ignoranza accidentale dell'errore: il compilatore costringe a gestire entrambe le branche (successo e fallimento).
Problema: Era necessario rendere la gestione degli errori il più sicura e leggibile possibile, escludere errori "nascosti", e aumentare l'affidabilità del codice senza dover utilizzare eccezioni.
Soluzione: Result<T, E> è un'enumerazione con due varianti: Ok(T) in caso di successo e Err(E) in caso di errore. Ciò costringe a gestire esplicitamente gli errori, oppure a ignorarli esplicitamente usando unwrap o aspettarsi panics. Inoltre, l'operatore ? rende i modelli comuni di propagazione degli errori concisi.
Esempio di codice:
use std::fs::File; use std::io::{self, Read}; fn read_file(path: &str) -> Result<String, io::Error> { let mut file = File::open(path)?; let mut contents = String::new(); file.read_to_string(&mut contents)?; Ok(contents) }
Caratteristiche chiave:
?.Si può sempre usare l'operatore ? per propagare automaticamente un errore verso l'alto?
No, solo se il tipo di errore della funzione corrisponde al tipo dell'espressione a destra del ?. Se i tipi non sono compatibili, è necessario effettuare una conversione esplicita dell'errore tramite il metodo .map_err() o il proprio tipo.
Esempio di codice:
fn f() -> Result<(), String> { let _f = File::open("foo").map_err(|e| e.to_string())?; Ok(()) }
Si può lasciare il risultato di Result non utilizzato se non si è semplicemente interessati agli errori?
No, il compilatore darà un avviso o un errore se il risultato di tipo Result non viene gestito. È necessario chiamare .unwrap(), oppure chiamare esplicitamente .ok()/.err()/let _ = ... o registrare correttamente l'errore.
Cosa succede se si chiama .unwrap() su un Result con errore?
Verrà attivato un panic! e l'esecuzione del programma verrà interrotta, di solito portando a un problema critico. Pertanto, unwrap() è accettabile solo quando si garantisce il successo.
let _ = ...;) senza registrazioneUno sviluppatore ha deciso di leggere la configurazione da un file e ha utilizzato unwrap() sul risultato della lettura.
Vantaggi:
Svantaggi:
Gli errori durante la lettura della configurazione vengono registrati e restituiti verso l'alto nel stack di chiamate utilizzando Result + operatore ?.
Vantaggi:
Svantaggi: