Suche…


Einführung

Rust verwendet die Result<T, E> , um behebbare Fehler während der Ausführung anzuzeigen. Nicht behebbare Fehler verursachen Panik , ein eigenes Thema.

Bemerkungen

Details zur Fehlerbehandlung werden in The Rust Programming Language (aka The Book) beschrieben.

Häufige Result-Methoden

use std::io::{Read, Result as IoResult};
use std::fs::File;

struct Config(u8);

fn read_config() -> IoResult<String> {
    let mut s = String::new();
    let mut file = File::open(&get_local_config_path())
        // or_else closure is invoked if Result is Err.
        .or_else(|_| File::open(&get_global_config_path()))?;
    // Note: In `or_else`, the closure should return a Result with a matching
    //       Ok type, whereas in `and_then`, the returned Result should have a
    //       matching Err type.
    let _ = file.read_to_string(&mut s)?;
    Ok(s)
}

struct ParseError;

fn parse_config(conf_str: String) -> Result<Config, ParseError> {
    // Parse the config string...
    if conf_str.starts_with("bananas") {
        Err(ParseError)
    } else {
        Ok(Config(42))
    }
}

fn run() -> Result<(), String> {
    // Note: The error type of this function is String. We use map_err below to
    //       make the error values into String type
    let conf_str = read_config()
        .map_err(|e| format!("Failed to read config file: {}", e))?;
    // Note: Instead of using `?` above, we can use `and_then` to wrap the let
    //       expression below.
    let conf_val = parse_config(conf_str)
        .map(|Config(v)| v / 2) // map can be used to map just the Ok value
        .map_err(|_| "Failed to parse the config string!".to_string())?;

    // Run...

    Ok(())
}

fn main() {
    match run() {
        Ok(_) => println!("Bye!"),
        Err(e) => println!("Error: {}", e),
    }
}

fn get_local_config_path() -> String {
    let user_config_prefix = "/home/user/.config";
    // code to get the user config directory
    format!("{}/my_app.rc", user_config_prefix)
}

fn get_global_config_path() -> String {
    let global_config_prefix = "/etc";
    // code to get the global config directory
    format!("{}/my_app.rc", global_config_prefix)
}

Wenn die Konfigurationsdateien nicht vorhanden sind, wird Folgendes ausgegeben:

Error: Failed to read config file: No such file or directory (os error 2)

Wenn die Analyse fehlgeschlagen ist, wird Folgendes ausgegeben:

Error: Failed to parse the config string!

Hinweis: Wenn das Projekt wächst, wird es umständlich, Fehler mit diesen grundlegenden Methoden ( docs ) zu behandeln, ohne dass Informationen zum Ursprung und Ausbreitungspfad von Fehlern verloren gehen. Außerdem ist es definitiv eine schlechte Praxis, Fehler vorzeitig in Strings zu konvertieren, um mehrere Fehlertypen wie oben dargestellt zu behandeln. Ein viel besserer Weg ist die Verwendung der Kistenfehler error-chain .

Benutzerdefinierte Fehlertypen

use std::error::Error;
use std::fmt;
use std::convert::From;
use std::io::Error as IoError;
use std::str::Utf8Error;

#[derive(Debug)] // Allow the use of "{:?}" format specifier
enum CustomError {
    Io(IoError),
    Utf8(Utf8Error),
    Other,
}

// Allow the use of "{}" format specifier
impl fmt::Display for CustomError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            CustomError::Io(ref cause) => write!(f, "I/O Error: {}", cause),
            CustomError::Utf8(ref cause) => write!(f, "UTF-8 Error: {}", cause),
            CustomError::Other => write!(f, "Unknown error!"),
        }
    }
}

// Allow this type to be treated like an error
impl Error for CustomError {
    fn description(&self) -> &str {
        match *self {
            CustomError::Io(ref cause) => cause.description(),
            CustomError::Utf8(ref cause) => cause.description(),
            CustomError::Other => "Unknown error!",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match *self {
            CustomError::Io(ref cause) => Some(cause),
            CustomError::Utf8(ref cause) => Some(cause),
            CustomError::Other => None,
        }
    }
}

// Support converting system errors into our custom error.
// This trait is used in `try!`.
impl From<IoError> for CustomError {
    fn from(cause: IoError) -> CustomError {
        CustomError::Io(cause)
    }
}
impl From<Utf8Error> for CustomError {
    fn from(cause: Utf8Error) -> CustomError {
        CustomError::Utf8(cause)
    }
}

Durch Ursachen iterieren

Für Debugging-Zwecke ist es oft hilfreich, die Hauptursache eines Fehlers zu finden. Um einen Fehlerwert zu untersuchen, der std::error::Error implementiert:

use std::error::Error;

let orig_error = call_returning_error();

// Use an Option<&Error>. This is the return type of Error.cause().
let mut err = Some(&orig_error as &Error);

// Print each error's cause until the cause is None.
while let Some(e) = err {
    println!("{}", e);
    err = e.cause();
}

Grundlegende Fehlerberichterstattung und -behandlung

Result<T, E> ist ein enum der zwei Varianten aufweist: Ok(T) zeigt die erfolgreiche Ausführung mit einem aussagekräftigen Ergebnis vom Typ T an und Err(E) zeigt das Auftreten eines unerwarteten Fehlers während der Ausführung an, der durch einen Wert des Typs E .

enum DateError {
    InvalidDay,
    InvalidMonth,
}

struct Date {
    day: u8,
    month: u8,
    year: i16,
}

fn validate(date: &Date) -> Result<(), DateError> {
    if date.month < 1 || date.month > 12 {
        Err(DateError::InvalidMonth)
    } else if date.day < 1 || date.day > 31 {
        Err(DateError::InvalidDay)
    } else {
        Ok(())
    }
}

fn add_days(date: Date, days: i32) -> Result<Date, DateError> {
    validate(&date)?; // notice `?` -- returns early on error
    // the date logic ...
    Ok(date)
}

Weitere Informationen finden Sie in den Dokumenten ? Operator.

Standard - Bibliothek enthält ein Error , das alle Fehlertypen empfohlen werden , zu implementieren. Eine Beispielimplementierung ist unten angegeben.

use std::error::Error;
use std::fmt;

#[derive(Debug)]
enum DateError {
    InvalidDay(u8),
    InvalidMonth(u8),
}

impl fmt::Display for DateError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &DateError::InvalidDay(day) => write!(f, "Day {} is outside range!", day),
            &DateError::InvalidMonth(month) => write!(f, "Month {} is outside range!", month),
        }
    }
}

impl Error for DateError {
    fn description(&self) -> &str {
        match self {
            &DateError::InvalidDay(_) => "Day is outside range!",
            &DateError::InvalidMonth(_) => "Month is outside range!",
        }
    }

    // cause method returns None by default
}

Hinweis: Im Allgemeinen sollte Option<T> nicht für die Meldung von Fehlern verwendet werden. Option<T> zeigt eine erwartete Möglichkeit des Nichtvorhandenseins eines Werts und einen einzigen einfachen Grund dafür an. Im Gegensatz dazu wird Result<T, E> verwendet, um unerwartete Fehler während der Ausführung zu melden, insbesondere wenn mehrere Fehlerarten vorhanden sind, um zwischen ihnen zu unterscheiden. Außerdem wird Result<T, E> nur als Rückgabewert verwendet. ( Eine alte Diskussion. )



Modified text is an extract of the original Stack Overflow Documentation
Lizenziert unter CC BY-SA 3.0
Nicht angeschlossen an Stack Overflow