Why does “break” not need a semicolon when ending a “loop”?

半世苍凉 提交于 2021-01-05 05:51:28

问题


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?


回答1:


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 // !
    }
};

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. 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:

  • Why do return expressions use semicolons when they're unnecessary?
  • What's the difference between using the return statement and omitting the semicolon in Rust?
  • How to statically assert the end of a function is unreachable



回答2:


The Rust Language Reference on Expression Statements:

An expression statement is one that evaluates an expression and ignores its result. As a rule, an expression statement's purpose is to trigger the effects of evaluating its expression.

An expression that consists of only a block expression or control flow expression, if used in a context where a statement is permitted, can omit the trailing semicolon.

I imagine this is purely for aesthetics and ergonomics, since almost everything is an expression in Rust. If the trailing semicolon was mandatory after all expressions then we'd have to terminate if-else blocks (which are also expressions) with semicolons which looks terrible:

if {
    // do something
} else {
    // do something else
}; // <- gross

Similarly, we can omit the trailing semicolon on all control flow expressions because they produce control flow, so the typical function of the semicolon, which is to discard the expression's result and evaluate to () instead, becomes irrelevant.

fn five() -> i32 {
    return 5 // to semicolon or not to semicolon? it doesn't matter
}

In the above example it doesn't make a difference if we terminate return 5 with a semicolon or not since nothing can "capture" the result of that expression anyway since it produces control flow. Same would be true for other control flow expressions like break and continue.



来源:https://stackoverflow.com/questions/65024479/why-does-break-not-need-a-semicolon-when-ending-a-loop

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!