Акумулиране на `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)

Източник: http://xion.io/post/code/rust-iter-patterns.html