Idiomatic way to iterate over Result instances

Hi everyone!

Given this code:

fn do_something(item: T) { }

fn items() -> impl Iterator<Item = Result<T, E>> {
    // …
}

fn use_items() -> Result<(), E> {
    for item in items() {
        let item = item?; // ←

        // now, `item` is `T`
        do_something(item);
    }

    Ok(())
}

Is there any way to remove the let item = item? line? So I can write something like this:

fn use_items() -> Result<(), E> {
    for item in items().[???] {
        do_something(item);
    }

    Ok(())
}

No, not really. The let item = item?; should be pretty idiomatic AFAIK.

2 Likes

I personally often desugar the for-loop, (and the same technique works with async iterators).

let iter = items();
while let Some(item) = iter.next()? {

This doesn’t do anything to handle any Err(…) items. And if you’d just use a while let Some(Ok(…))-style pattern, you’d be ignoring, not propagating the errors. Wait, I missed the “?”. But aren’t you missing something like a .transpose() call?

while let Some(item) = iter.next().transpose()? {…}

Maybe, I definitely feel like I've at least done .next().await? on a stream before and had it work but maybe I'm thinking of something out of context.

You can use itertools::Itertools::map_ok like this:

use itertools::Itertools;

fn use_items() -> Result<(), E> {
    items().map_ok(|item| {
        do_something(item);
    }).collect()
}

or in this simple case, even:

fn use_items() -> Result<(), E> {
    items().map_ok(do_something).collect()
}

(Playground)

2 Likes

If you want to do this in non-terminal position in the function, then try_collect can help with type inference.

fn use_items() -> Result<(), E> {
    items().map_ok(|item| {
        do_something(item);
    }).try_collect()?;

    // do something else here, too…

    Ok(())
}

Note that this approach (with either of the collect functions) doesn’t work as nicely if you had any other usage of ? or perhaps break or return in the for-loop.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.