Rust is an expression-oriented language. This means that most constructs including control-flow constructs are expressions. An expression followed by a semicolon ; is a statement, whose effect is to evaluate the expression and discard its result. Therefore, the distinction between expression and statement is less important. However, some expressions diverge and that's a little weird if you're coming from other languages.
break counter * 2 is an expression. What is the type and value of this expression? It is a diverging expression. It has no value, and the type is a type ! that has no values. Imagine writing:
let foo = break counter * 2;
Ask what is the type of foo. One cannot have the effect of break, which is essentially a goto, while also returning a value and continuing the loop. The type of a break expression therefore is always a type without values. An uninhabited type, a type without any values, may seem odd but conceptually it's fine. It's the return type of functions that never return. It's the type of infinite loops, which can never evaluate to a value.
Yes, break counter * 2; is a statement which discards the value of the expression break counter * 2, but the value of the expression is not counter * 2.
What is the type of loop { ... }? By fiat, it is the type of the expressions within any break expressions in the loop. The value of the loop must come from one of the break expressions.
So, if you add some types:
fn main() {
// The type of counter is i32, because it is not
// suffixed with a different literal type, and no
// use below causes a different type to be inferred.
let mut counter: i32 = 0;
// The type of result is the type of the loop
// expression, which by definition is the type of
// the expressions passed to `break` within the
// loop. There is only one `break`, which is passed
// counter * 2, of type i32.
let result: i32 = loop {
counter += 1;
if counter == 10 {
// The type of this expression is !.
// Since a semicolon follows, the value
// is discarded, but the expression has no value.
break counter * 2;
}
};
println!("The result is {}", result);
}