Breaking out of for

I wish to break of a for loop, but the only way to do that is to wrap it in a loop:

    let res = 'found: loop {
        for (i, u) in some_vector.iter().enumerate() {
            if let Some(w) = is_good_one(u) {
                break 'found Some((i, w));
            }
        }
        break 'found None;
    };

    if let Some((i, target)) = res {
        some_vector.drain(i + 1..);
        ...;
    }

but now (I think it just started) Clippy thinks my loop is useless, sigh. It's not, but what is the ideomatic way to do this (I don't want to return at this point)?

Why not just use

    let mut res = None;    
    for (i, u) in some_vector.iter().enumerate() {
        if let Some(w) = is_good_one(u) {
            res = Some((i, w));
            break
        }
    }
2 Likes
let res = some_vector.iter()
    .enumerate()
    .filter_map(|(i, u)| Some((i, is_good_one(u)?))
    .next();

Edit: use @Michael-F-Bryan 's find_map below, I missed that one.

3 Likes

It depends on your preferred style, but I would normally rewrite the loop like this:

let res = some_vector.iter().enumerate().find_map(|(i, u)| {
    let w = is_good_one(u)?;
    Some((i, w))
});

Edit: Looks like @Hyeonu had almost the exact same thing in mind :sweat_smile:

9 Likes

I had a similar problem. I like the functional-style rewrites, but sometimes working with closures can be unhandy, e.g. if there's a short-circuit return (or ? operator) in the loop's body.

It'll be break with block, but it's unstable :frowning:

6 Likes

You can just extract the loop body into a function and return.

Thanks @zirconium-n, the single break is of course what I was looking for but what then if there were two nested loops and I was breaking out of the inner-most? I guess @chrefr's solution is what I'll ultimately need.

The other solutions implies more heavy handed rewrites which I wasn't looking for. They might be appropriate in particular instances, but they make the code harder to read, especially for people who might not be Rust-savy but needs to understand the flow regardless.

ADD: I didn't make it clear but the loop body examines many non-trivial conditions, so the functional style wouldn't work or at best be awkward.

I suggest you add your feedback to this issue.

1 Like

If that's is the case, maybe it's a hint that the code needs rewriting anyway?

Having multiple levels of nesting and introducing concepts like break labels would be just as hard for a new Rustacean to read as the iterator-based version.

1 Like