Итерирование по Result

При работе метода Iter::map может случиться ошибка, например:

fn main() {
    let strings = vec!["tofu", "93", "18"];
    let numbers: Vec<_> = strings
        .into_iter()
        .map(|s| s.parse::<i32>())
        .collect();
    println!("Результаты: {:?}", numbers);
}

Давайте рассмотрим стратегии обработки этого.

Игнорирование неудачных элементов с filter_map()

filter_map вызывает функцию и отфильтровывает результаты, вернувшие None.

fn main() {
    let strings = vec!["tofu", "93", "18"];
    let numbers: Vec<_> = strings
        .into_iter()
        .map(|s| s.parse::<i32>())
        .filter_map(Result::ok)
        .collect();
    println!("Результаты: {:?}", numbers);
}

Сбой всей операции с collect()

Result реализует FromIter так что вектор из результатов (Vec<Result<T, E>>) может быть преобразован в результат с вектором (Result<Vec<T>, E>). Если будет найдена хотя бы одна Result::Err, итерирование завершится.

fn main() {
    let strings = vec!["tofu", "93", "18"];
    let numbers: Result<Vec<_>, _> = strings
        .into_iter()
        .map(|s| s.parse::<i32>())
        .collect();
    println!("Результаты: {:?}", numbers);
}

Та же самая техника может использоваться с Option.

Сбор всех корректных значений и ошибок с помощью 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);
    println!("Ошибки: {:?}", errors);
}

Если вы посмотрите на результаты работы, вы заметите, что они всё ещё обёрнуты в Result. Потребуется немного больше шаблонного кода, чтобы получить нужный результат.

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);
    println!("Ошибки: {:?}", errors);
}