Optionen und Standardwerte entpacken

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 werden wir verschiedene Möglichkeiten zur Entpackung eines Option untersuchen und auf einen Standardwert zurückgreifen, wenn es None ist, wobei Faktoren wie eager oder lazy Evaluation sowie die Frage, ob der leere Wert in situ geändert oder unberührt gelassen werden soll, berücksichtigt werden.

Hinweis: Wenn im Lab kein Dateiname angegeben ist, 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.

Entpacken von Optionen und Standardwerten

Es gibt mehrere Möglichkeiten, eine Option zu entpacken und auf einen Standardwert zurückzugreifen, wenn sie None ist. Um diejenige auszuwählen, die unseren Anforderungen entspricht, müssen wir die folgenden Aspekte berücksichtigen:

  • Brauchen wir eager oder lazy Evaluation?
  • Brauchen wir den ursprünglichen leeren Wert unberührt zu lassen oder ihn in situ zu modifizieren?

or() ist kettenbar, wertet eager aus, behält leeren Wert unberührt

or() ist kettenbar und wertet seinen Argument eager aus, wie im folgenden Beispiel gezeigt. Beachten Sie, dass die Argumente von or eager ausgewertet werden, sodass die Variable, die an or übergeben wird, bewegt wird.

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let apple = Some(Fruit::Apple);
    let orange = Some(Fruit::Orange);
    let no_fruit: Option<Fruit> = None;

    let first_available_fruit = no_fruit.or(orange).or(apple);
    println!("first_available_fruit: {:?}", first_available_fruit);
    // first_available_fruit: Some(Orange)

    // `or` bewegt sein Argument.
    // Im obigen Beispiel hat `or(orange)` ein `Some` zurückgegeben, sodass `or(apple)` nicht aufgerufen wurde.
    // Aber die Variable mit dem Namen `apple` wurde dennoch bewegt und kann nicht mehr verwendet werden.
    // println!("Variable apple was moved, so this line won't compile: {:?}", apple);
    // TODO: Entkommentieren Sie die obige Zeile, um den Compilerfehler zu sehen
 }

or_else() ist kettenbar, wertet lazy aus, behält leeren Wert unberührt

Eine weitere Möglichkeit ist die Verwendung von or_else, die ebenfalls kettenbar ist und lazy ausgewertet wird, wie im folgenden Beispiel gezeigt:

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let apple = Some(Fruit::Apple);
    let no_fruit: Option<Fruit> = None;
    let get_kiwi_as_fallback = || {
        println!("Providing kiwi as fallback");
        Some(Fruit::Kiwi)
    };
    let get_lemon_as_fallback = || {
        println!("Providing lemon as fallback");
        Some(Fruit::Lemon)
    };

    let first_available_fruit = no_fruit
     .or_else(get_kiwi_as_fallback)
     .or_else(get_lemon_as_fallback);
    println!("first_available_fruit: {:?}", first_available_fruit);
    // Providing kiwi as fallback
    // first_available_fruit: Some(Kiwi)
}

get_or_insert() wertet eager aus, modifiziert leeren Wert in situ

Um sicherzustellen, dass eine Option einen Wert enthält, können wir get_or_insert verwenden, um sie in situ mit einem Fallback-Wert zu modifizieren, wie im folgenden Beispiel gezeigt. Beachten Sie, dass get_or_insert seinen Parameter eager auswertet, sodass die Variable apple bewegt wird:

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let mut my_fruit: Option<Fruit> = None;
    let apple = Fruit::Apple;
    let first_available_fruit = my_fruit.get_or_insert(apple);
    println!("first_available_fruit is: {:?}", first_available_fruit);
    println!("my_fruit is: {:?}", my_fruit);
    // first_available_fruit is: Apple
    // my_fruit is: Some(Apple)
    //println!("Variable named `apple` is moved: {:?}", apple);
    // TODO: Entkommentieren Sie die obige Zeile, um den Compilerfehler zu sehen
}

get_or_insert_with() wertet lazy aus, modifiziert leeren Wert in situ

Anstatt explizit einen Wert zum Fallback bereitzustellen, können wir eine Closure an get_or_insert_with übergeben, wie folgt:

#[derive(Debug)]
enum Fruit { Apple, Orange, Banana, Kiwi, Lemon }

fn main() {
    let mut my_fruit: Option<Fruit> = None;
    let get_lemon_as_fallback = || {
        println!("Providing lemon as fallback");
        Fruit::Lemon
    };
    let first_available_fruit = my_fruit
     .get_or_insert_with(get_lemon_as_fallback);
    println!("first_available_fruit is: {:?}", first_available_fruit);
    println!("my_fruit is: {:?}", my_fruit);
    // Providing lemon as fallback
    // first_available_fruit is: Lemon
    // my_fruit is: Some(Lemon)

    // Wenn die Option einen Wert hat, bleibt er unverändert und die Closure wird nicht aufgerufen
    let mut my_apple = Some(Fruit::Apple);
    let should_be_apple = my_apple.get_or_insert_with(get_lemon_as_fallback);
    println!("should_be_apple is: {:?}", should_be_apple);
    println!("my_apple is unchanged: {:?}", my_apple);
    // Die Ausgabe lautet wie folgt. Beachten Sie, dass die Closure `get_lemon_as_fallback` nicht aufgerufen wird
    // should_be_apple is: Apple
    // my_apple is unchanged: Some(Apple)
}

Zusammenfassung

Herzlichen Glückwunsch! Sie haben das Lab "Entpacken von Optionen und Standardwerten" abgeschlossen. Sie können in LabEx weitere Labs absolvieren, um Ihre Fähigkeiten zu verbessern.