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.