Control Flow & match
if as an expression, loop with break values, for over ranges and iterators, and exhaustive match.
Rust's control flow looks familiar, with one important difference: most constructs are expressions that produce values. And match, Rust's switch, must cover every possible case — the compiler checks.
Branches and loops
classify's if/else if/else is the function's return value: there is no return keyword and no semicolon on the last expression.
break n; leaves the loop and makes n the value of the whole loop expression.
for (i, name) in ...iter().enumerate() gives an index and a reference to each element.
match arms can use ranges (1..=9), guards (x if x % 2 == 0) and _ for everything else.
Expressions and semicolons
fn double(x: i32) -> i32 { x * 2; } fn double(x: i32) -> i32 { x * 2 }
The semicolon makes x * 2 a statement, so the function returns () and does not compile. Leave it off the final expression.
What is the value of let y = if x > 0 { 1 } else { -1 };?
1 or -1: if is an expression. Both branches must have the same type.
Why must a match be exhaustive?
So every possible value is handled; the compiler rejects a match that misses a case, which prevents forgotten cases when new variants are added.