Search code examples
rustcontrol-flow

Return a value from labeled loops


We can return a value from loops with break, for example:

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

        if counter == 10 {
            break counter * 2;
        }
    };

    println!("The result is {result}");
}

And we can break the outer loops using labels, but is there a way to also return a value while breaking outer loops?

fn main() {
    let mut count = 0;
    'counting_up: loop {
        println!("count = {count}");
        let mut remaining = 10;

        loop {
            println!("remaining = {remaining}");
            if remaining == 9 {
                break;
            }
            if count == 2 {
                break 'counting_up; // <-- Want to retun a value here
            }
            remaining -= 1;
        }

        count += 1;
    }
    println!("End count = {count}");
}


Solution

  • Loops in Rust are expressions, and while most loops evaluate to (), you can break with a value, including breaking to outer labels. In the following example, this is accomplished by break 'counting_up Some(1) and assigning the loop's value via let foo: Option<usize> = 'counting_up: loop {

    Notice that the compiler will enforce that all control flow paths evaluate to the same type (that is, the type of foo). If your loop does not produce a value in all cases, you can simply use Option, as in the example below.

    fn main() {
        let mut count = 0;
    
        // Assign the loop's value to `foo`
        let foo: Option<usize> = 'counting_up: loop {
            println!("count = {count}");
            let mut remaining = 10;
    
            loop {
                println!("remaining = {remaining}");
                if remaining == 9 {
                    break;
                }
                if count == 2 {
                    // Value found
                    break 'counting_up Some(1);
                }
                if count == 3 {
                    // Break early, assign `None` to `foo`
                    break 'counting_up None;
                }
                remaining -= 1;
            }
    
            count += 1;
    
            if count >= 42 {
                // break from 'counting_loop, assign `None` to `foo`
                break None;
            }
        };
    
        println!("End count = {foo:?}");
    }