Gestione robusta degli errori con `Result`
Implementi una gestione idiomatica degli errori utilizzando l’enum `Result`, l’operatore `?` e tipi di errore personalizzati per applicazioni resilienti.
Gestione robusta degli errori con `Result` è una lezione Learn Rust Coding gratuita su CoddyKit. Questa è la lezione 3 di 3. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Learn Rust Coding, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Learn Rust Coding include 3 lezioni in totale.
Gestire gli errori in Rust
Gli errori fanno parte della programmazione. In Rust si distinguono due tipi principali: errori recuperabili e non recuperabili.
- Gli errori non recuperabili segnalano generalmente bug e causano l'arresto del programma con
panic!. - Gli errori recuperabili indicano che qualcosa è andato storto, ma possono essere gestiti, come nel caso di un file non trovato.
Rust aiuta a gestire con eleganza gli errori recuperabili.
`panic!` e `Result`
Quando si verifica un errore non recuperabile, Rust chiama la macro panic!. Questa svolge lo stack e termina il programma, generalmente stampando un messaggio di errore.
Per gli errori recuperabili, Rust usa l'enum Result. Questo enum indica se un'operazione è riuscita (Ok) o non è riuscita (Err), consentendo al programma di decidere cosa fare in seguito.
L'enum `Result`
L'enum Result è definito concettualmente come:
enum Result<T, E> {
Ok(T),
Err(E),
}
Trappresenta il tipo di valore restituito in caso di successo.Erappresenta il tipo di errore restituito in caso di fallimento.
È un modo potente per dichiarare esplicitamente che una funzione potrebbe fallire.
Eseguire il matching su `Result`
Il modo più comune per gestire un Result consiste nell'usare un'espressione match. In questo modo è possibile eseguire blocchi di codice diversi a seconda che il Result sia Ok o Err.
Provi a eseguire questo esempio, che tenta di analizzare un numero:
fn parse_and_add(text: &str) -> Result<i32, std::num::ParseIntError> {
text.parse::<i32>()
}
fn main() {
let num_str = "123";
let result = parse_and_add(num_str);
match result {
Ok(num) => println!("Parsed number: {}", num),
Err(e) => println!("Error parsing: {}", e),
}
let bad_str = "abc";
let bad_result = parse_and_add(bad_str);
match bad_result {
Ok(num) => println!("Parsed number: {}", num),
Err(e) => println!("Error parsing: {}", e),
}
}Estrarre i valori da Result (con attenzione!)
A volte si può essere certi che un'operazione non fallirà oppure si desidera che il programma vada in panic in caso contrario. Metodi come unwrap() ed expect() estraggono il valore Ok.
unwrap(): restituisce il valoreOkoppure va in panic se il risultato èErr.expect("message"): funziona comeunwrap(), ma consente di fornire un messaggio personalizzato per il panic.
Li utilizzi con moderazione, soprattutto nei test o quando un errore è davvero irrecuperabile.
Introduzione all'operatore `?`
Scrivere istruzioni match per ogni Result può diventare ripetitivo. L'operatore ? offre una scorciatoia concisa per propagare gli errori.
Quando viene inserito dopo un'espressione che restituisce un Result, ? svolge due operazioni:
- Se il
ResultèErr, restituisce immediatamente l'Errdalla funzione corrente. - Se il
ResultèOk, estrae il valoreOke continua l'esecuzione.
L'operatore `?` in azione
L'operatore ? rende molto più semplice scrivere funzioni che potrebbero fallire. Ricordi che la funzione che usa ? deve a sua volta restituire un Result (o un Option).
Osservi come ? semplifica la gestione degli errori in questo esempio di lettura di un file:
use std::fs::File;
use std::io::{self, Read};
fn read_username_from_file() -> Result<String, io::Error> {
let mut f = File::open("hello.txt")?; // Propagates error if file not found
let mut s = String::new();
f.read_to_string(&mut s)?; // Propagates error if read fails
Ok(s)
}
fn main() {
// Create a dummy file for the example to work
// In a real scenario, this file might not exist
std::fs::write("hello.txt", "CoddyKit User").unwrap();
match read_username_from_file() {
Ok(username) => println!("Username: {}", username),
Err(e) => println!("Error reading username: {}", e),
}
// Clean up the dummy file
std::fs::remove_file("hello.txt").unwrap();
}Tipi di errore personalizzati
A volte i tipi di errore integrati non sono abbastanza specifici. È possibile definire tipi di errore personalizzati usando gli enum per rappresentare le diverse modalità di errore della propria applicazione.
In questo modo i messaggi di errore risultano più chiari e i chiamanti possono gestire gli errori specifici in modo diverso.
Un modello comune consiste nel creare un enum che elenchi tutti gli errori possibili che una funzione o un modulo può produrre.
Far funzionare `?` con gli errori personalizzati
Affinché l'operatore ? converta automaticamente un errore di livello inferiore (come io::Error) nel proprio tipo di errore personalizzato, l'enum dell'errore personalizzato deve implementare il trait From per quell'errore di livello inferiore.
In questo modo si indica a Rust come convertire un tipo di errore in un altro, rendendo fluida la propagazione degli errori.
use std::io;
use std::fs::File;
use std::io::Read;
#[derive(Debug)]
enum MyError {
Io(io::Error),
Parse(std::num::ParseIntError)
}
impl From<io::Error> for MyError {
fn from(error: io::Error) -> Self {
MyError::Io(error)
}
}
impl From<std::num::ParseIntError> for MyError {
fn from(error: std::num::ParseIntError) -> Self {
MyError::Parse(error)
}
}
fn read_config(path: &str) -> Result<i32, MyError> {
let mut file = File::open(path)?; // io::Error converted to MyError::Io
let mut contents = String::new();
file.read_to_string(&mut contents)?; // io::Error converted to MyError::Io
let value = contents.trim().parse::<i32>()?; // ParseIntError converted to MyError::Parse
Ok(value)
}
fn main() {
// Create a dummy file for the example
std::fs::write("config.txt", "123").unwrap();
match read_config("config.txt") {
Ok(val) => println!("Config value: {}", val),
Err(e) => println!("Failed to read config: {:?}", e),
}
std::fs::remove_file("config.txt").unwrap(); // Clean up
// Example with a non-existent file
match read_config("non_existent.txt") {
Ok(val) => println!("Config value: {}", val),
Err(e) => println!("Failed to read config: {:?}", e),
}
}Verifichi la propria comprensione
Consideri il seguente frammento di codice Rust. Quale sarà l'output se il file data.txt NON esiste?
Riepilogo: gestione robusta degli errori
Ha acquisito padronanza della gestione robusta degli errori in Rust!
- Enum
Result: distingue traOk(T)per il successo eErr(E)per il fallimento. match: il modo fondamentale per gestire le varianti diResult.- Operatore
?: una potente scorciatoia per propagare i valoriErrlungo lo stack delle chiamate. - Errori personalizzati: consente di definire i propri tipi di errore usando gli enum, per una maggiore chiarezza e una gestione specifica.
- Trait
From: abilita la conversione fluida degli errori di livello inferiore nei propri tipi di errore personalizzati quando si usa?.
Ora esplori le funzionalità avanzate del sistema dei tipi!
Domande Frequenti
La lezione «Gestione robusta degli errori con `Result`» è gratuita?
Sì — il testo completo di «Gestione robusta degli errori con `Result`» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Learn Rust Coding, passa a CoddyKit PRO. Il corso Learn Rust Coding include 3 lezioni in totale.
Cosa imparerò in «Gestione robusta degli errori con `Result`»?
Implementi una gestione idiomatica degli errori utilizzando l’enum `Result`, l’operatore `?` e tipi di errore personalizzati per applicazioni resilienti. Eserciti Learn Rust Coding con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare Learn Rust Coding?
Non è richiesta alcuna esperienza precedente. Learn Rust Coding su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 3.
Quanto tempo richiede la lezione «Gestione robusta degli errori con `Result`»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione Learn Rust Coding?
Sì. Ogni lezione Learn Rust Coding include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- Organizzare il codice con i moduli
- Gestire le dipendenze con i crate
- Gestione robusta degli errori con `Result`