Lecții din modul (2/2)
Gestionarea erorilor și ? Operator
Filosofia lui Rust vă încurajează să recunoașteți posibilitatea erorilor în mod explicit și să vă structurați codul pentru a le gestiona înainte ca programul să fie compilat.
Erorile din Rust sunt împărțite în două categorii principale: erori irecuperabile (care provoacă încetarea imediată prin intermediul macrocomenzii panic!) și erori recuperabile (gestionate folosind tipul Result<T, E>).
Potrivirea tipului și modelului Rezultatul<T, E>
Cele mai multe erori recuperabile returnează un tip Result<T, E>, care este o enumerare definită ca:
enum Result<T, E> {
Ok(T),
Err(E),
}Putem folosi potrivirea modelului pentru a inspecta rezultatul:
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),
};
}Propagarea erorilor cu operatorul ?
Când implementăm o funcție, în loc să gestionăm eroarea direct în ea, deseori dorim să returnăm eroarea apelantului, astfel încât acesta să poată decide ce să facă. Acest proces se numește propagarea erorilor.
Rust oferă operatorul ? ca scurtătură sintactică pentru a propaga erori. Dacă valoarea unui Result este Ok, valoarea interioară a lui Ok este returnată de expresie; dacă este Err, eroarea Err este returnată din întreaga funcție curentă ca și cum am fi folosit un return Err(...).
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] Operatorul
?poate fi utilizat numai în funcțiile care returnează un tip compatibil cu valoarea căreia i se aplică (de obiceiResult,Optionsau tipuri care implementeazăFromResidual).
Erori personalizate
Ne putem defini propriile tipuri de erori personalizate prin implementarea trăsăturii std::fmt::Display (și opțional std::error::Error) pentru a oferi o reprezentare care poate fi citită de om a erorii:
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 {}Încercați-l singur
Exercițiul 1: Citirea unui fișier cu ? operator
Completați funcția read_username_from_file astfel încât să folosească ? operator pentru a propaga erorile generate prin deschiderea fișierului și citirea conținutului acestuia în șirul numelui de utilizator.
Afișează indiciu
Adăugați caracterul `?` după`File::open(...)`și după`username_file.read_to_string(...)` pentru a propaga erori.
Soluție disponibilă după 3 încercări
Exercițiul 2: Analizați și dublați un număr
Scrieți o funcție numită parse_and_double care acceptă o referință de șir &str și returnează un Rezultat<i32, std::num::ParseIntError>. Funcția ar trebui să analizeze șirul folosind val.parse::<i32>() cu ? pentru a propaga erorile de analiză, iar la succes returnează valoarea dublată încapsulată în Ok.
Afișează indiciu
Utilizați `val.parse::<i32>()?` pentru a analiza șirul și a propaga eroarea, apoi returnați`Ok(num \* 2)`.
Soluție disponibilă după 3 încercări
Exercițiul 3: Definirea unei erori personalizate
Definiți o structură goală numită CustomError. Implementați caracteristica std::fmt::Display pentru aceasta scriind „Si e verificato un errore personalizzato” ca mesaj de eroare în metoda fmt.
Afișează indiciu
Declarați `struct CustomError;`și implementați Display scriind`write!(f, "Si e verificato un error personalizzato")`în cadrul metodei`fmt`.
Soluție disponibilă după 3 încercări