Control Flow in Rust
Learn conditionals, match expressions, and loops in Rust with practical Docker-ready examples covering if/else, match, loop, while, and for
Control flow is how a program decides what to do next—branching on conditions and repeating work. Rust gives you the familiar tools (if, while, for) but with a twist that reflects its multi-paradigm roots: in Rust, if and match are expressions, not just statements. That means they produce values you can bind to variables, which leads to concise, assignment-free code.
Rust also leans on its functional heritage with match, an exhaustive pattern-matching construct far more powerful than a C-style switch. The compiler forces you to handle every possible case, eliminating a whole class of “forgot a branch” bugs at compile time. Combined with strong static typing, this makes Rust’s control flow both expressive and safe.
In this tutorial you’ll learn how to branch with if/else, use if as an expression, pattern-match with match, and iterate with Rust’s three loop forms: loop, while, and for. You’ll also see loop control with break and continue, including the unique ability of loop to return a value.
Conditionals with if / else
The basic conditional looks like other C-family languages, but note there are no parentheses around the condition, and the body braces are required even for a single line.
Create a file named conditionals.rs:
| |
Because if is an expression, the second example assigns its result directly to parity. Both branches must return the same type (here, &str), and the compiler enforces that. This replaces the ternary operator (?:) that Rust deliberately omits.
Pattern Matching with match
match is Rust’s most powerful branching tool. It compares a value against a series of patterns and runs the first that fits. Crucially, match must be exhaustive—every possible value has to be covered, often via the _ wildcard. Like if, match is an expression.
Create a file named matching.rs:
| |
The 1..=5 syntax is an inclusive range pattern. The final arm other binds the unmatched value to a name so you can use it—a common alternative to the bare _ wildcard when you want the value.
Loops: loop, while, and for
Rust has three loop keywords. loop runs forever until you break; while runs as long as a condition holds; and for iterates over a range or collection. A standout feature: break inside a loop can return a value.
Create a file named loops.rs:
| |
Note let mut—loop counters must be declared mutable, since Rust variables are immutable by default. The for i in 1..=3 form is the idiomatic way to count; Rust has no C-style for (i = 0; i < n; i++) loop because ranges and iterators cover those cases more safely.
Loop Control with break and continue
break exits a loop early and continue skips to the next iteration—the same as most languages. Rust adds loop labels (written 'name:) so you can break out of an outer loop from within an inner one.
Create a file named loop_control.rs:
| |
The for value in nums loop iterates the array by value (each i32 is copied). The labeled 'outer break jumps all the way out of both loops at once—without a label, break would only exit the inner loop.
Running with Docker
Compile and run each example using the official Rust image. The rustc compiler produces an executable named after the source file (minus the .rs extension).
| |
Expected Output
Running conditionals.rs:
7 is greater than 5
7 is odd
Running matching.rs:
7 is in category: high
Slow down
Running loops.rs:
loop result: 50
while countdown: 3
while countdown: 2
while countdown: 1
for range: 1
for range: 2
for range: 3
Running loop_control.rs:
for item: 10
for item: 30
for item: 40
stopping at x=2, y=2
Key Concepts
ifis an expression — It returns a value, so you can writelet x = if cond { a } else { b }. Both branches must produce the same type. Rust has no ternary operator because it doesn’t need one.matchis exhaustive — The compiler requires every possible case to be handled, catching missing branches at compile time. Use_or a binding name for the catch-all arm.- Range patterns —
1..=5matches inclusively inmatcharms and drivesforloops, replacing manual index counters. - Three loop forms —
loop(infinite untilbreak),while(condition-controlled), andfor(iterates ranges/collections). There is no C-stylefor(;;)loop. breakcan return a value — Onlyloopsupportsbreak value, letting a loop compute and hand back a result.- Loop labels — Annotate loops with
'label:and usebreak 'labelorcontinue 'labelto control outer loops from within nested ones. - Mutability is explicit — Loop counters and accumulators need
let mut, since bindings are immutable by default.
Comments
Loading comments...
Leave a Comment