jevoso5871
jevoso5871

Reputation: 21

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

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 `?`

Upvotes: 2

Views: 1160

Answers (3)

spdrman
spdrman

Reputation: 1503

Here you go:

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

Upvotes: 2

Chayim Friedman
Chayim Friedman

Reputation: 71005

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.

Upvotes: 3

Aplet123
Aplet123

Reputation: 35512

There's actually a Sum instance for Result<T, E> that fits this usecase perfectly:

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

Upvotes: 2

Related Questions