rustrust-result

How do I stop iteration and return an error when Iterator::map returns a Result::Err?


I have a function that returns a Result:

fn find(id: &Id) -> Result<Item, ItemError> {
    // ...
}

Then another using it like this:

let parent_items: Vec<Item> = parent_ids.iter()
    .map(|id| find(id).unwrap())
    .collect();

How do I handle the case of failure inside any of the map iterations?

I know I could use flat_map and in this case the error results would be ignored:

let parent_items: Vec<Item> = parent_ids.iter()
    .flat_map(|id| find(id).into_iter())
    .collect();

Result's iterator has either 0 or 1 items depending on the success state, and flat_map will filter it out if it's 0.

However, I don't want to ignore errors, I want to instead make the whole code block just stop and return a new error (based on the error that came up within the map, or just forward the existing error).

How do I best handle this in Rust?


Solution

  • Result implements FromIterator, so you can move the Result outside and iterators will take care of the rest (including stopping iteration if an error is found).

    #[derive(Debug)]
    struct Item;
    type Id = String;
    
    fn find(id: &Id) -> Result<Item, String> {
        Err(format!("Not found: {:?}", id))
    }
    
    fn main() {
        let s = |s: &str| s.to_string();
        let ids = vec![s("1"), s("2"), s("3")];
    
        let items: Result<Vec<_>, _> = ids.iter().map(find).collect();
        println!("Result: {:?}", items);
    }
    

    Playground