Iterating over Results
An Iter::map operation might fail, for example:
1. fn main() {
2. let strings = vec!["tofu", "93", "18"];
3. let possible_numbers: Vec<_> = strings
4. .into_iter()
5. .map(|s| s.parse::<i32>())
6. .collect();
7. println!("Results: {:?}", possible_numbers);
8. }
Let’s step through strategies for handling this.
Ignore the failed items with filter_map()
filter_map calls a function and filters out the results that are None.
1. fn main() {
2. let strings = vec!["tofu", "93", "18"];
3. let numbers: Vec<_> = strings
4. .into_iter()
5. .map(|s| s.parse::<i32>())
6. .filter_map(Result::ok)
7. .collect();
8. println!("Results: {:?}", numbers);
9. }
Fail the entire operation with collect()
Result implements FromIter so that a vector of results (Vec<Result<T, E>>)
can be turned into a result with a vector (Result<Vec<T>, E>). Once an
Result::Err is found, the iteration will terminate.
1. fn main() {
2. let strings = vec!["tofu", "93", "18"];
3. let numbers: Result<Vec<_>, _> = strings
4. .into_iter()
5. .map(|s| s.parse::<i32>())
6. .collect();
7. println!("Results: {:?}", numbers);
8. }
This same technique can be used with Option.
Collect all valid values and failures with partition()
1. fn main() {
2. let strings = vec!["tofu", "93", "18"];
3. let (numbers, errors): (Vec<_>, Vec<_>) = strings
4. .into_iter()
5. .map(|s| s.parse::<i32>())
6. .partition(Result::is_ok);
7. println!("Numbers: {:?}", numbers);
8. println!("Errors: {:?}", errors);
9. }
When you look at the results, you’ll note that everything is still wrapped in
Result. A little more boilerplate is needed for this.
1. fn main() {
2. let strings = vec!["tofu", "93", "18"];
3. let (numbers, errors): (Vec<_>, Vec<_>) = strings
4. .into_iter()
5. .map(|s| s.parse::<i32>())
6. .partition(Result::is_ok);
7. let numbers: Vec<_> = numbers.into_iter().map(Result::unwrap).collect();
8. let errors: Vec<_> = errors.into_iter().map(Result::unwrap_err).collect();
9. println!("Numbers: {:?}", numbers);
10. println!("Errors: {:?}", errors);
11. }
