Итерирование по 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);
}