Modulelessen (2/2)
Foutafhandeling en de ? Exploitant
De filosofie van Rust moedigt je aan om de mogelijkheid van fouten expliciet te onderkennen en je code zodanig te structureren dat deze wordt afgehandeld voordat het programma wordt gecompileerd.
Fouten in Rust zijn onderverdeeld in twee hoofdcategorieën: onherstelbare fouten (die onmiddellijke beëindiging veroorzaken via de macro panic!) en herstelbare fouten (beheerd met het type Result<T, E>).
Het resultaat<T, E> Type- en patroonmatching
De meeste herstelbare fouten retourneren het type Result<T, E>, een opsomming die is gedefinieerd als:
enum Result<T, E> {
Ok(T),
Err(E),
}We kunnen patroonmatching gebruiken om het resultaat te inspecteren:
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),
};
}Foutpropagatie met de operator ?
Bij het implementeren van een functie willen we, in plaats van de fout direct daarin af te handelen, de fout vaak terugsturen naar de aanroeper, zodat deze kan beslissen wat hij moet doen. Dit proces wordt foutvoortplanting genoemd.
Rust biedt de operator ? als een syntactische snelkoppeling om fouten door te geven. Als de waarde van een Result Ok is, wordt de innerlijke waarde van Ok geretourneerd door de expressie; als het Err is, wordt de fout Err geretourneerd door de gehele huidige functie alsof we een return Err(...) hadden gebruikt.
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)
}[!BELANGRIJK] De operator
?kan alleen worden gebruikt in functies die een type retourneren dat compatibel is met de waarde waarop het wordt toegepast (meestalResult,Option, of typen dieFromResidualimplementeren).
Aangepaste fouten
We kunnen onze eigen aangepaste fouttypen definiëren door de eigenschap std::fmt::Display (en optioneel std::error::Error) te implementeren om een voor mensen leesbare weergave van de fout te bieden:
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 {}Probeer het zelf
Oefening 1: Een bestand lezen met de ? exploitant
Voltooi de functie read_username_from_file zodat deze de ? operator om fouten door te geven die worden gegenereerd door het openen van het bestand en het lezen van de inhoud ervan in de gebruikersnaamreeks.
Toon hint
Voeg het teken `?` toe na`File::open(...)`en na`username_file.read_to_string(...)` om fouten door te geven.
Oplossing beschikbaar na 3 pogingen
Oefening 2: Een getal ontleden en verdubbelen
Schrijf een functie met de naam parse_and_double die een tekenreeksreferentie &str accepteert en een Resultaat<i32, std::num::ParseIntError> retourneert. De functie moet de tekenreeks parseren met behulp van val.parse::<i32>() met ? om parseerfouten door te geven en bij succes de dubbele waarde terug te geven, verpakt in Ok.
Toon hint
Gebruik `val.parse::<i32>()?`om de string te parseren en de fout door te geven, en retourneer vervolgens `Ok(num \* 2)`.
Oplossing beschikbaar na 3 pogingen
Oefening 3: Een aangepaste fout definiëren
Definieer een lege structuur met de naam CustomError. Implementeer de std::fmt::Display-eigenschap ervoor door 'Si e verificato un errore personalizzato' te schrijven als de foutmelding in de fmt-methode.
Toon hint
Declareer `struct CustomError;`en implementeer Display door`write!(f, "Si e verificato un errore personalizzato")`in de`fmt`methode te schrijven.
Oplossing beschikbaar na 3 pogingen