04. Control Flow (if · loop · while · for · break-with-value)
Rust's `if` is an expression — you can write `let x = if cond { 1 } else { 2 }`. This lesson covers `loop` / `while` / `for`, Rust-specific touches like attaching a value to `break`, labeled break / continue across nested loops, and `for` over ranges and iterators.
What you'll learn
- 1Understand `if` is an expression and use it as a value
- 2Pick the right one between `loop` / `while` / `for`
- 3Return a value from `loop` via `break value`
- 4Break out of nested loops cleanly with labels
- 5Iterate with ranges (`0..10`, `0..=10`) and iterators
Overview
Rust has no `cond ? a : b` ternary. It doesn't need one — `if` itself produces a value, so the same expressiveness comes naturally. This consistency keeps code short and readable.
Core Concepts
1) if is an expression
let n = 10;
let kind = if n % 2 == 0 { "even" } else { "odd" };
println!("{}", kind); // evenEach branch must produce the same type. One arm returning `"even"` and the other `42` is a compile error.
2) loop — infinite, exits via break
- Unconditional infinite loop
- `break value` makes that value the result of the `loop` expression
- Labels (`'outer:`) target which loop break/continue applies to
3) while — runs while condition is true
Skipped entirely if the condition starts false. For index-based traversal `for` is usually nicer.
4) for — iterator traversal
- `for x in 0..10` — 0,1,...,9 (exclusive upper)
- `for x in 0..=10` — 0,1,...,10 (inclusive)
- `for x in &v` — iterate Vec / slice
Hands-on Examples
Returning a value from `loop` — handy for search:
fn main() {
let arr = [3, 7, 11, 13, 17];
let target = 11;
let idx = loop {
let mut i = 0;
while i < arr.len() {
if arr[i] == target { break i as i32; }
i += 1;
}
break -1;
};
println!("index = {}", idx); // 2
}Labels exit nested loops:
fn main() {
'outer: for i in 0..5 {
for j in 0..5 {
if i + j == 6 {
println!("found ({}, {})", i, j);
break 'outer;
}
}
}
}Ranges and iterators with `for`:
fn main() {
for i in 0..3 { println!("i={}", i); } // 0,1,2
for i in 1..=3 { println!("j={}", i); } // 1,2,3
let v = vec![10, 20, 30];
for x in &v { println!("x={}", x); }
for (idx, x) in v.iter().enumerate() {
println!("{}-{}", idx, x);
}
}Common Mistakes
Q. Where's C-style `for (i = 0; i < n; i++)`?
A. Rust doesn't have it. `for i in 0..n` covers the common case, and `.iter().enumerate()` covers the rest. Off-by-one bugs go down too.
Q. What if `if` arms have different types?
A. Compile error. `let x = if c { 1 } else { "two" }` won't fly. Make types match, or wrap them in an enum.
Q. What's `while let`?
A. A `while` with pattern matching. `while let Some(v) = iter.next() { ... }` loops while the iterator yields Some. Covered in the pattern-matching lesson.
Recap
- `if` is an expression — use it on the right-hand side of `let`
- `loop` is infinite, `break value` returns from it
- `for in range` / `for in iterator` are the most common loop forms
- Use labels to break out of nested loops precisely
Try It Yourself
- Sum every even number from 1 to 100 using `for` and `if`
- Use `loop + break value` to compute sqrt(2) by Newton's method in 5 iterations
- Find the first `(i, j)` in a 2D grid where `i + j == 7` using a labeled break
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗