What is the idiomatic way to propagate error from value inside map statement in Rust?

Viewed 75

I have a function which returns a Result<u32, SomeError>. I want to collect four values from this function, and collect them to sum them up. How can you propagate the error inside the map operator? I want to stop on the first error, and propagate the error up to the function which called it

Works

(0..4)
    .map(|_| self.consume().unwrap())
    .collect::<Vec<u32>>()
    .iter()
    .sum::<u32>();

Does not work

(0..4)
    .map(|_| self.consume()?)
    .collect::<Vec<u32>>()
    .iter()
    .sum::<u32>();

The compiler error is

.map(|_| self.consume()?)
     ----^^^^^^^^^^^^^^^----------------------
     |   |
     |   cannot use the `?` operator in a closure that returns `u32`
     this function should return `Result` or `Option` to accept `?`
3 Answers

map() is just an iterator adapater. It cannot propagate the error itself, since it doesn't run the code that can produce it. The executor of the code here is sum() (actually, collect(), but it is redundant here) and thus it should deal with the error (or a replacement).

In this case, you can exploit the fact that Result implements Sum, allowing you to sum into Result<T, E>:

(0..4).map(|_| self.consume()).sum::<Result<u32, _>>()?;

collect() also does the same, so you can collect into Result<Vec<T>, E> for example.

Here you go:

(0..4)
    .map(|_| self.consume())
    .collect::<Result<Vec<u32>, _>>()?
    .iter()
    .sum::<u32>();
Related