How do I return an Result::Error within a map function of an Option

Let's say I have a function that return a Result

fn do_stuff() -> Result<ResultType, ErrorType> {

}

The implementation of this function is using a struct provided by a third party provider hence I cant really show the exact code, but the thing about this struct is, it provides an iterator and the elements are retrieved as some. so something like this

fn do_stuff() -> Result<ResultType, ErrorType> {

    (third_party: ThirdParty).iter().map(|s| {
        s // -> is Option<Stuff>
    })

}

Now there needs to be certain operation that needs to be performed on s. And these operations can fail so they return a Result

fn do_stuff() -> Result<ResultType, ErrorType> {

    (third_party: ThirdParty).iter().map(|s| {
        match s {
           Some(thing) => {
                 let output = operate_on_thing(thing)
            },
           None => {
              None
           }
        }
    })
}

The problem now is, if the operation fails, I want the error within the map to bubble up to be the error result returned from the function. That is

fn do_stuff() -> Result<ResultType, ErrorType> {

    (third_party: ThirdParty).iter().map(|s| {
        match s {
           Some(thing) => {
                 let output = operate_on_thing(thing)
                 // if output is an Error, then return from this mapping and have that Error value
                // be the return of the do_stuff function. if it is not an error then Some s is successfully mapped
            },
           None => {
              None
           }
        }
    })
}

Apologies I can't reproduce with exact code.

Any thoughts on how to go about this?

Sounds like you want an early return on err which is irrelevant to the Option type:

fn do_stuff(arr: &[Option<i32>]) -> Result<ResultType, Error> {
    let mut res = Ok(ResultType::default()); // suppose you want a default ok value when all elements are none
    for s in arr {
        res = match s {
            Some(thing) => Ok(operate_on_thing(*thing)?),
            None => continue,
        };
    }
    res
}

Or

...
arr.iter().flatten().try_for_each(|thing| operate_on_thing(*thing).map(|r| res = Ok(r)))?;
...

Rust Playground

1 Like

There are plenty of great tools in the std lib for dealing with iterators of Results
Here's a good summary

I tried using ? but I got some error about you cannot early return in a function that maps a closure from Result

If you use ? in the map function, the error won't be propagated to the outside of the closure.

So you'll need an API designed for fallible functions. That's exactly what try_* family does (see Try in std::ops - Rust), like try_for_each.

1 Like