I recently found myself in a situation where I had to either collect all values if none of them had an error, or collect all errors. Since I didn't want to fast-fail through collecting to Result<Vec<T>, E>, I made a function which collects to Result<Vec<T>, Vec<E>>:
fn collect_or_errors<I, T, E>(iter: I) -> Result<Vec<T>, Vec<E>>
where
I: Iterator<Item = Result<T, E>>,
{
iter.fold(Ok(Vec::new()), |mut until_now, new| {
match (&mut until_now, new) {
(Ok(okays), Ok(new)) => okays.push(new),
(Err(errors), Err(new)) => errors.push(new),
(Ok(_), Err(error)) => until_now = Err(vec![error]),
_ => (),
};
until_now
})
}
fn main() {
let iter = vec![Err("meow"), Ok(2), Err("doge"), Ok(7), Ok(30)].into_iter();
let _ = dbg!(collect_or_errors(iter));
}
Two specific things, feel free to note any else, too:
- Can I make this function more generic, like allowing
FromIteratorinstead of theVecs? I don't think so, since I need some kind of buffer to actuallly push to, but that may just be me. - The
matchlooks pretty convoluted, can I make it any simpler than it already is?
you can do that before the .partition_result()