Акумулиране на `Result`-ове с `collect()`
Да речем, че имаме итератор, който ни дава резултати. Може да са дошли примерно от четене на списък от файлове, или някаква друга операция, която може да се провали:
let items: Vec<Result<u32, &'static str>> =
vec![Ok(3), Err("Error!"), Ok(14)];
Ако искаме да извлечем вектор от успешните стойности, лесно можем да направим нещо такова:
let successes: Vec<_> = items.into_iter().filter_map(Result::ok).collect();
След като итерираме, използваме Result::ok
, за да конвертираме Result
-овете в Option
-и, и filter_map
-а ще събере стойностите само от Some
-овете.
Това е супер, но игнорира всякакви грешки. А ако искаме да върнем грешка, в случай, че ударим на първата такава? Бихме могли да итерираме ръчно, и да съберем резултата в един Result<Vec<_>, _>
, но се оказва, че метода collect()
е достатъчно умен, за да го направи вместо нас:
let items: Vec<Result<u32, &'static str>> =
vec![Ok(3), Ok(17), Ok(14)];
let result: Result<Vec<_>, _> = items.into_iter().collect();
println!("{:?}", result);
// => Ok([3, 17, 14])
let items: Vec<Result<u32, &'static str>> =
vec![Ok(3), Err("First error!"), Ok(14), Err("Second error!")];
let result: Result<Vec<_>, _> = items.into_iter().collect();
println!("{:?}", result);
// => Err("First error!")
В случай, че няма грешки, получаваме Result
, който държи вектор от всички резултати. В случай, че итерирането удари на Err
, директно се връща грешката, без да се продължава итерацията. Магия! (не съвсем, вижте имплементацията на Result
за FromIterator
)