I love how elegantly Rust can convert from Vec<Result<.. into Result<Vec<.., but for more complex nested types I'm quickly finding myself in stinkier and stinkier code. Is this as clean as it gets?:
pub type Error = Box<dyn std::error::Error>;
fn main() {
let a: Vec<i32> = vec![];
let b: Vec<Result<Vec<i32>, Error>> = a
.into_iter()
.map(|_| Ok(vec![]))
.collect::<Vec<_>>();
let c: Result<Vec<Vec<i32>>, Error> = b.into_iter().collect();
let d: Result<Vec<i32>, Error> = c.map(|v| v.into_iter().flatten().collect::<Vec<_>>());
}
Needing to iterate over the outer Vec twice is a bit annoying though, so if I knew there would be a lot of them I would probably write the thing as a loop in a helper function and use ? to avoid passing around the Results.
fn unroll(items: Vec<Result<Vec<i32>, Error>>) -> Result<Vec<i32>, Error> {
let mut unrolled = Vec::new();
for result in items {
unrolled.extend(result?);
}
Ok(unrolled)
}
There should also be a specialisation for Extend with a Vec<i32> that does a simple memcpy(), so that should also be pretty fast.
I suspect that most of the time will be taken up by reallocation, so you can get a performance improvement by using Vec::with_capacity(items.len()).
A maximally performant approach would probably reuse the allocation for items, but I don't know of any efficient way of doing that without unsafe code.
This is beautifully simple. I'll keep coming back to this answer for years to come as a great example for how my initial functional approach is just more complexity than it's probably worth. Mutability has handsome benefits clearly shown here.