Andere Verwendung von?

RustRustBeginner
Jetzt üben

This tutorial is from open-source community. Access the source code

💡 Dieser Artikel wurde von AI-Assistenten übersetzt. Um die englische Version anzuzeigen, können Sie hier klicken

Einführung

In diesem Lab wird erklärt, dass der ?-Operator in Rust verwendet werden kann, um Fehler automatisch in den gewünschten Rückgabetyp umzuwandeln, wodurch die explizite Fehlerbehandlung mit map_err entfällt.

Hinweis: Wenn das Lab keinen Dateinamen angibt, können Sie einen beliebigen Dateinamen verwenden. Beispielsweise können Sie main.rs verwenden und es mit rustc main.rs &&./main kompilieren und ausführen.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL rust(("Rust")) -.-> rust/BasicConceptsGroup(["Basic Concepts"]) rust(("Rust")) -.-> rust/DataTypesGroup(["Data Types"]) rust(("Rust")) -.-> rust/FunctionsandClosuresGroup(["Functions and Closures"]) rust(("Rust")) -.-> rust/DataStructuresandEnumsGroup(["Data Structures and Enums"]) rust(("Rust")) -.-> rust/AdvancedTopicsGroup(["Advanced Topics"]) rust/BasicConceptsGroup -.-> rust/variable_declarations("Variable Declarations") rust/DataTypesGroup -.-> rust/integer_types("Integer Types") rust/DataTypesGroup -.-> rust/string_type("String Type") rust/DataTypesGroup -.-> rust/type_casting("Type Conversion and Casting") rust/FunctionsandClosuresGroup -.-> rust/function_syntax("Function Syntax") rust/FunctionsandClosuresGroup -.-> rust/expressions_statements("Expressions and Statements") rust/DataStructuresandEnumsGroup -.-> rust/method_syntax("Method Syntax") rust/AdvancedTopicsGroup -.-> rust/traits("Traits") rust/AdvancedTopicsGroup -.-> rust/operator_overloading("Traits for Operator Overloading") subgraph Lab Skills rust/variable_declarations -.-> lab-99249{{"Andere Verwendung von?"}} rust/integer_types -.-> lab-99249{{"Andere Verwendung von?"}} rust/string_type -.-> lab-99249{{"Andere Verwendung von?"}} rust/type_casting -.-> lab-99249{{"Andere Verwendung von?"}} rust/function_syntax -.-> lab-99249{{"Andere Verwendung von?"}} rust/expressions_statements -.-> lab-99249{{"Andere Verwendung von?"}} rust/method_syntax -.-> lab-99249{{"Andere Verwendung von?"}} rust/traits -.-> lab-99249{{"Andere Verwendung von?"}} rust/operator_overloading -.-> lab-99249{{"Andere Verwendung von?"}} end

Andere Verwendung von ?

Bemerken Sie im vorherigen Beispiel, dass unsere unmittelbare Reaktion auf das Aufrufen von parse darin besteht, den Fehler von einem Bibliotheksfehler in einen boxing-Fehler zu map:

.and_then(|s| s.parse::<i32>())
  .map_err(|e| e.into())

Da dies eine einfache und häufige Operation ist, wäre es praktisch, wenn sie weggelassen werden könnte. Leider kann dies nicht, weil and_then nicht ausreichend flexibel ist. Wir können jedoch stattdessen ? verwenden.

? wurde zuvor als entweder unwrap oder return Err(err) erklärt. Dies ist nur größtenteils wahr. Es bedeutet tatsächlich unwrap oder return Err(From::from(err)). Da From::from ein Konversionswerkzeug zwischen verschiedenen Typen ist, bedeutet dies, dass, wenn Sie ? verwenden, wo der Fehler in den Rückgabetyp umgewandelt werden kann, er automatisch konvertiert wird.

Hier überschreiben wir das vorherige Beispiel mit ?. Dadurch wird der map_err wegfallen, wenn From::from für unseren Fehlertyp implementiert ist:

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

// Ändern Sie den Alias in `Box<dyn error::Error>`.
type Result<T> = std::result::Result<T, Box<dyn error::Error>>;

#[derive(Debug)]
struct EmptyVec;

impl fmt::Display for EmptyVec {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "ungültiges erstes Element zum Verdoppeln")
    }
}

impl error::Error for EmptyVec {}

// Die gleiche Struktur wie zuvor, aber anstatt alle `Result` und `Option`
// entlang zu ketten, verwenden wir `?`, um den inneren Wert sofort zu extrahieren.
fn double_first(vec: Vec<&str>) -> Result<i32> {
    let first = vec.first().ok_or(EmptyVec)?;
    let parsed = first.parse::<i32>()?;
    Ok(2 * parsed)
}

fn print(result: Result<i32>) {
    match result {
        Ok(n)  => println!("Das erste verdoppelt ist {}", n),
        Err(e) => println!("Fehler: {}", e),
    }
}

fn main() {
    let numbers = vec!["42", "93", "18"];
    let empty = vec![];
    let strings = vec!["tofu", "93", "18"];

    print(double_first(numbers));
    print(double_first(empty));
    print(double_first(strings));
}

Dies ist jetzt tatsächlich ziemlich sauber. Im Vergleich zum ursprünglichen panic ist es sehr ähnlich, unwrap-Aufrufe mit ? zu ersetzen, nur dass die Rückgabetypen Result sind. Daher müssen sie auf der obersten Ebene zerstückt werden.

Zusammenfassung

Herzlichen Glückwunsch! Sie haben das Lab "Andere Verwendung von ?" abgeschlossen. Sie können in LabEx weitere Labs ausprobieren, um Ihre Fähigkeiten zu verbessern.