Control flow, the Rust way
Worked examples
Read the claim, then run it and check the machine agrees. One at a time — nothing here is taken on trust.
fn main() {
let score = 72;
let status = if score >= 60 { "pass" } else { "fail" };
println!("score {score}: {status}");
// both arms must agree on the type:
// let n = if score > 50 { 5 } else { "six" };
// ^ error[E0308]: `if` and `else` have incompatible types
// ...and a value-producing if needs an else:
// let n = if score > 50 { 5 };
// ^ error[E0317]: `if` may be missing an `else` clause
let bonus = if score > 90 { 10 } else { 0 };
println!("bonus: {bonus}");
}
One binding, one type, chosen at runtime by the condition — the
if expression replaces the ternary operator and its cousin
x if cond else y from Python. The two commented lines are the
two ways it can go wrong, with the exact error codes rustc
answers with: arms of different types (E0308), and a missing
else when a value is expected (E0317).
fn main() {
// the search-loop idiom: break carries the answer out
let mut p = 1;
let first_power_over_100 = loop {
if p > 100 {
break p;
}
p *= 2;
};
println!("first power of 2 over 100: {first_power_over_100}");
// while: classic, condition-driven, evaluates to ()
let mut fuel = 3;
while fuel > 0 {
println!("burning... {fuel}");
fuel -= 1;
}
println!("empty");
}
The loop computes 128 and hands it straight into the binding —
no result variable mutated from inside, no boolean flag. The
while underneath is exactly what you expect from any language;
its only Rust twist is that it can't produce a value. When a loop
exists to FIND something, reach for loop + break value.
fn main() {
for i in 1..4 {
print!("{i} ");
}
println!(" <- 1..4 excludes the end");
for i in (1..=3).rev() {
print!("{i} ");
}
println!(" <- .rev() counts down");
for level in [0, 7, 42] {
let label = match level {
0 => "empty",
1..=9 => "single digit",
_ => "big",
};
println!("{level}: {label}");
}
}
Prints 1 2 3, then 3 2 1, then labels three levels. The match
is an expression feeding a binding, same as the if-expression —
and it's checked: remove the _ arm and the program stops
compiling with E0004, which lists the exact uncovered ranges
(i32::MIN..=-1_i32 and 10_i32..=i32::MAX). The compiler read
your branches more carefully than your reviewer will.
Check the concept
One question at a time. Unsure? Revisit the lecture, then answer.
The challenge
Pass the quiz to unlock the challenge — your code will still be waiting here.