7.1Control flow introduction
Every program you've written so far has been a straight-line program: it runs the same statements, in the same order, every single time. Read two numbers, add them, print the sum, done. Run it a thousand times and it walks the same path a thousand times.
The path a program actually takes through its statements is called its execution path. Useful programs need more than one. A login screen behaves differently for a right password and a wrong one. A game keeps asking for moves until somebody wins. The falling-ball program from lesson 4.x had to be told how many seconds to simulate, because it had no way to notice the ball hitting the ground on its own.
A statement that lets the program choose between execution paths is called a control flow statement, and when the program takes a path other than straight-on to the next statement, we say it has branched.
You've met one already: if, in lesson 4.7. It has company. Here's the full map of this chapter:
| Category | Tools | Where |
|---|---|---|
| Conditionals | if / else, match | 4.7, 7.2, 7.3 |
| Loops | loop, while, for | 7.4, 7.5 |
| Jumps | break, continue, return | 7.6 (and return since 2.2) |
| Halts | std::process::exit, panic! | 7.8 |
Recursion (a function calling itself, lesson 7.7) isn't a statement, but it bends execution paths in the same spirit, so it lives in this chapter too.
What's missing from the map
If you've programmed in a C-family language, you may notice some famous names absent. That's not an oversight; it's housecleaning.
No goto. C and C++ let you jump from any line to any labeled line in the same function. In 1968, Edsger Dijkstra wrote the most famous complaint in programming history about it ("Go To Statement Considered Harmful"): programs built on goto turn into a tangle where you can't follow any thread to its end, what programmers affectionately call spaghetti code. Rust doesn't have it. The one job goto did defensibly, escaping a deeply nested loop, has a dedicated, tamer tool here (loop labels, lesson 7.6).
No do-while. C++ has a second loop syntax whose condition is checked at the bottom instead of the top. Rust gets the same effect with the one loop it has, as you'll see in lesson 7.4.
No switch. C's switch statement only works on integers, and execution falls through from one case into the next unless you remember to write break, a default behavior so error-prone that compilers issue warnings about using it. Rust replaces it wholesale with match, which works on far more than integers and doesn't fall through. It's the chapter's biggest new idea, and lesson 7.3 introduces it.
No exceptions. C++ programs can throw an error up through the call stack to whoever agrees to catch it. Rust handles errors with values instead, using a type called Result. That story gets its own chapter (chapter 12).
Key insight
Each deletion is the same trade: Rust removes a construct that made bugs easy to write, and keeps (or builds in) the part people actually needed. You've seen this pattern since the mandatory braces of lesson 4.7, and this chapter is where it pays off most visibly.
There's one more absence worth naming: nothing in the table above is new machinery. You already know that blocks are expressions (1.11) and that if produces values (4.7). Rust's control flow is built from those same two ideas, applied again and again. match produces values. Even loop can produce a value, which sounds absurd right up until lesson 7.6 shows you why it's useful.
By the end of this chapter you'll write the course's first real program: a number guessing game that loops, reads input, branches on comparisons, and quits when you win (lesson 7.10). And those six nearly identical report lines that closed chapter 4? Lesson 7.5 deletes five of them.
No quiz this time. Next up: if has a few habits we haven't covered.