Lær at programmere i Rust · Lektion

Robust fejlhåndtering med `Result`

Implementer idiomatisk fejlhåndtering med enumen `Result`, operatoren `?` og brugerdefinerede fejltyper til robuste applikationer.

Lektion 3 af 311 trin

Robust fejlhåndtering med `Result` er en gratis Lær at programmere i Rust-lektion på CoddyKit. Dette er lektion 3 af 3. Du kan læse alle 3 lektioner i dette læringsspor gratis i deres fulde længde — derefter låser CoddyKit PRO alle lektioner op samt praktiske øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Den er en del af læringsforløbet i Lær at programmere i Rust, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. Lær at programmere i Rust-kurset indeholder 3 lektioner i alt.

Håndtering af fejl i Rust

Fejl er en del af programmering. I Rust skelner vi mellem to hovedtyper: håndterbare og uhåndterbare fejl.

  • Uhåndterbare fejl er som regel tegn på fejl i programmet og får programmet til at stoppe med panic!.
  • Håndterbare fejl betyder, at noget gik galt, men at det kan håndteres, f.eks. når en fil ikke blev fundet.

Rust hjælper dig med at håndtere håndterbare fejl på en elegant måde.

`panic!` kontra `Result`

Når der opstår en uhåndterbar fejl, kalder Rust makroen panic!. Den afvikler stakken og afslutter dit program, normalt efter at have udskrevet en fejlmeddelelse.

Til håndterbare fejl bruger Rust enum'en Result. Denne enum fortæller dig, om en handling lykkedes (Ok) eller mislykkedes (Err), så dit program kan beslutte, hvad der skal ske derefter.

Enum'en `Result`

Enum'en Result er konceptuelt defineret sådan:

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

  • T repræsenterer typen af den værdi, der returneres ved succes.
  • E repræsenterer typen af den fejl, der returneres ved fejl.

Det er en effektiv måde eksplicit at angive, at en funktion kan mislykkes.

Match på `Result`

Den mest almindelige måde at håndtere en Result på er at bruge et match-udtryk. Det giver dig mulighed for at udføre forskellige kodeblokke afhængigt af, om Result er Ok eller Err.

Prøv at køre dette eksempel, som forsøger at fortolke et tal:

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

Udpakning af resultater (med omtanke!)

Nogle gange er du måske sikker på, at en handling ikke vil mislykkes, eller du ønsker, at dit program går ned, hvis den gør. Metoder som unwrap() og expect() udtrækker Ok-værdien.

  • unwrap(): Returnerer Ok-værdien eller udløser en panic, hvis resultatet er Err.
  • expect("message"): Det samme som unwrap(), men lader dig angive en brugerdefineret panic-meddelelse.

Brug dem sparsomt, primært i tests eller når en fejl virkelig er uhåndterbar.

Introduktion til operatoren `?`

Det kan blive gentagende at skrive match-udtryk for hver Result. Operatoren ? er en kort og præcis genvej til fejlvideregivelse.

Når den placeres efter et udtryk, der returnerer en Result, gør ? to ting:

  • Hvis Result er Err, returnerer den straks Err fra den aktuelle funktion.
  • Hvis Result er Ok, udpakker den Ok-værdien og fortsætter udførelsen.

Operatoren `?` i praksis

Operatoren ? gør funktioner, der kan mislykkes, meget enklere at skrive. Husk, at funktionen, der bruger ?, selv skal returnere en Result (eller Option).

Se, hvordan ? forenkler fejlhåndtering i dette eksempel, der læser en fil:

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

Brugerdefinerede fejltyper

Nogle gange er de indbyggede fejltyper ikke specifikke nok. Du kan definere dine egne brugerdefinerede fejltyper ved hjælp af enum'er, der repræsenterer forskellige fejlscenarier i din applikation.

Det gør dine fejlmeddelelser tydeligere og giver kaldende kode mulighed for at håndtere specifikke fejl forskelligt.

Et almindeligt mønster er at oprette en enum, der oplister alle de fejl, en funktion eller et modul kan generere.

Sådan får du `?` til at fungere med brugerdefinerede fejl

For at operatoren ? automatisk kan konvertere en fejl på lavere niveau (f.eks. io::Error) til din brugerdefinerede fejltype skal din brugerdefinerede fejl-enum implementere traiten From for fejlen på lavere niveau.

Det fortæller Rust, hvordan én fejltype konverteres til en anden, så fejlvideregivelsen fungerer problemfrit.

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

Test din forståelse

Se på følgende Rust-kodestykke. Hvad bliver outputtet, hvis filen data.txt IKKE findes?

Opsummering: Robust fejlhåndtering

Du har fået styr på robust fejlhåndtering i Rust!

  • Enum'en Result: Skelner mellem Ok(T) ved succes og Err(E) ved fejl.
  • match: Den grundlæggende måde at håndtere varianter af Result på.
  • Operatoren ?: En effektiv genvej til at videregive Err-værdier op gennem kaldestakken.
  • Brugerdefinerede fejl: Definer dine egne fejltyper ved hjælp af enum'er for større tydelighed og specifik håndtering.
  • Traiten From: Muliggør problemfri konvertering af fejl på lavere niveau til dine brugerdefinerede fejltyper ved brug af ?.

Gå derefter videre til avancerede funktioner i typesystemet!

Gratis at komme i gang

Lær Rust med en AI-underviser — gratis

Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.

Kurser
39
Lektioner
144

Ofte stillede spørgsmål

Er lektionen “Robust fejlhåndtering med `Result`” gratis?

Ja — alle 3 lektioner i læringssporet Lær at programmere i Rust, inklusive “Robust fejlhåndtering med `Result`”, kan læses gratis i deres fulde længde her på webstedet. Derefter låser CoddyKit PRO alle lektioner op samt interaktive øvelser med en indbygget kodeeditor og en AI-underviser døgnet rundt. Lær at programmere i Rust-kurset indeholder 3 lektioner i alt.

Hvad lærer jeg i “Robust fejlhåndtering med `Result`”?

Implementer idiomatisk fejlhåndtering med enumen `Result`, operatoren `?` og brugerdefinerede fejltyper til robuste applikationer. Du øver dig i Lær at programmere i Rust med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.

Skal jeg have erfaring for at begynde på Lær at programmere i Rust?

Der kræves ingen tidligere erfaring. Lær at programmere i Rust på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 3 af 3.

Hvor lang tid tager lektionen “Robust fejlhåndtering med `Result`”?

De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.

Kan jeg skrive og køre kode i denne Lær at programmere i Rust-lektion?

Ja. Alle Lær at programmere i Rust-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.

Alle lektioner i dette kursus

  1. Organisering af kode med moduler
  2. Håndtering af afhængigheder med crates
  3. Robust fejlhåndtering med `Result`
← Tilbage til Lær at programmere i Rust