Search code examples
loopsrustsyntaxbreakkeyword

Why does "break" not need a semicolon when ending a "loop"?


Excerpt from Chapter 3.5 of the Rust Book:

we use the break keyword with the value counter * 2. After the loop, we use a semicolon to end the statement that assigns the value to result.

Plus the code snippet:

fn main() {
    let mut counter = 0;

    let result = loop {
        counter += 1;

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

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

I understand how this works and why the result is 20, but I noticed that if I remove the semicolon on the line that contains the break keyword, the program is equivalent.

Why is the semicolon optional in this case?


Solution

  • A shorter example:

    let _: i32 = loop {
        if true {
            break 3; // ()
        }
    };
    

    That is just another example where the semi-colon does not interfere with the intended outcome. For one, the insertion of a semi-colon introduces an expression statement, which evaluates to the unit type (). As the loops and if expressions continue to admit a code block evaluating to the same type (), then all types are in conformance.

    let _: i32 = loop {
        if true {
            break 3 // ! coerced to ()
        }
    };
    

    If the semi-colon is taken away, the break is evaluated to the never type !, which coerces to any other type. This means that it will fulfill any type expected by the outer scope. In this case, break 3 alone also becomes () to fulfill the if expression. So all is well all the same, so long as you don't try to append any other statement before the end of the if block.

    Both break and return evaluate to !, as their side effects imply that the program will not go through with the natural workflow.

    See also: