Iterieren über Ergebnisse

Beginner

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

Einführung

In diesem Lab untersuchen wir verschiedene Strategien, um die Möglichkeit von Fehlern zu behandeln, während wir über eine Sammlung von Results in Rust iterieren.

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.

Iterieren über Results

Eine Iter::map-Operation kann fehlschlagen, z.B.:

fn main() {
    let strings = vec!["tofu", "93", "18"];
    let numbers: Vec<_> = strings
     .into_iter()
     .map(|s| s.parse::<i32>())
     .collect();
    println!("Results: {:?}", numbers);
}

Schauen wir uns die Strategien an, um dies zu behandeln.

Ignorieren Sie die fehlgeschlagenen Elemente mit filter_map()

filter_map ruft eine Funktion auf und filtert die Ergebnisse, die None sind.

fn main() {
    let strings = vec!["tofu", "93", "18"];
    let numbers: Vec<_> = strings
     .into_iter()
     .filter_map(|s| s.parse::<i32>().ok())
     .collect();
    println!("Results: {:?}", numbers);
}

Sammeln Sie die fehlgeschlagenen Elemente mit map_err() und filter_map()

map_err ruft eine Funktion mit dem Fehler auf, so dass wir sie, indem wir sie der vorherigen filter_map-Lösung hinzufügen, während des Iterierens beiseite legen können.

fn main() {
    let strings = vec!["42", "tofu", "93", "999", "18"];
    let mut errors = vec![];
    let numbers: Vec<_> = strings
     .into_iter()
     .map(|s| s.parse::<u8>())
     .filter_map(|r| r.map_err(|e| errors.push(e)).ok())
     .collect();
    println!("Numbers: {:?}", numbers);
    println!("Errors: {:?}", errors);
}

Den gesamten Vorgang mit collect() abbrechen

Result implementiert FromIterator, sodass ein Vektor von Ergebnissen (Vec<Result<T, E>>) in ein Ergebnis mit einem Vektor (Result<Vec<T>, E>) umgewandelt werden kann. Sobald ein Result::Err gefunden wird, wird die Iteration abgebrochen.

fn main() {
    let strings = vec!["tofu", "93", "18"];
    let numbers: Result<Vec<_>, _> = strings
     .into_iter()
     .map(|s| s.parse::<i32>())
     .collect();
    println!("Results: {:?}", numbers);
}

Dieselbe Technik kann mit Option verwendet werden.

Sammeln Sie alle gültigen Werte und Fehler mit partition()

fn main() {
    let strings = vec!["tofu", "93", "18"];
    let (numbers, errors): (Vec<_>, Vec<_>) = strings
     .into_iter()
     .map(|s| s.parse::<i32>())
     .partition(Result::is_ok);
    println!("Numbers: {:?}", numbers);
    println!("Errors: {:?}", errors);
}

Wenn Sie sich die Ergebnisse ansehen, werden Sie feststellen, dass alles immer noch in Result eingeschlossen ist. Dafür ist ein bisschen mehr Boilerplate erforderlich.

fn main() {
    let strings = vec!["tofu", "93", "18"];
    let (numbers, errors): (Vec<_>, Vec<_>) = strings
     .into_iter()
     .map(|s| s.parse::<i32>())
     .partition(Result::is_ok);
    let numbers: Vec<_> = numbers.into_iter().map(Result::unwrap).collect();
    let errors: Vec<_> = errors.into_iter().map(Result::unwrap_err).collect();
    println!("Numbers: {:?}", numbers);
    println!("Errors: {:?}", errors);
}

Zusammenfassung

Herzlichen Glückwunsch! Sie haben das Lab Iterieren über Results abgeschlossen. Sie können in LabEx weitere Labs ausprobieren, um Ihre Fähigkeiten zu verbessern.