]> git.proxmox.com Git - rustc.git/blame - src/doc/book/src/ch03-05-control-flow.md
New upstream version 1.60.0+dfsg1
[rustc.git] / src / doc / book / src / ch03-05-control-flow.md
CommitLineData
13cf67c4
XL
1## Control Flow
2
3c0e092e
XL
3The ability to run some code depending on if a condition is true, or run some
4code repeatedly while a condition is true, are basic building blocks in most
5programming languages. The most common constructs that let you control the flow
6of execution of Rust code are `if` expressions and loops.
13cf67c4
XL
7
8### `if` Expressions
9
10An `if` expression allows you to branch your code depending on conditions. You
11provide a condition and then state, “If this condition is met, run this block
12of code. If the condition is not met, do not run this block of code.”
13
14Create a new project called *branches* in your *projects* directory to explore
15the `if` expression. In the *src/main.rs* file, input the following:
16
17<span class="filename">Filename: src/main.rs</span>
18
19```rust
74b04a01 20{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-26-if-true/src/main.rs}}
13cf67c4
XL
21```
22
3c0e092e
XL
23All `if` expressions start with the keyword `if`, followed by a condition. In
24this case, the condition checks whether or not the variable `number` has a
25value less than 5. We place block of code to execute if the condition is true
26immediately after the condition inside curly brackets. Blocks of code
27associated with the conditions in `if` expressions are sometimes called *arms*,
28just like the arms in `match` expressions that we discussed in the [“Comparing
29the Guess to the Secret Number”][comparing-the-guess-to-the-secret-number]<!--
30ignore --> section of Chapter 2.
13cf67c4
XL
31
32Optionally, we can also include an `else` expression, which we chose
33to do here, to give the program an alternative block of code to execute should
34the condition evaluate to false. If you don’t provide an `else` expression and
35the condition is false, the program will just skip the `if` block and move on
36to the next bit of code.
37
38Try running this code; you should see the following output:
39
f035d41b 40```console
74b04a01 41{{#include ../listings/ch03-common-programming-concepts/no-listing-26-if-true/output.txt}}
13cf67c4
XL
42```
43
44Let’s try changing the value of `number` to a value that makes the condition
45`false` to see what happens:
46
47```rust,ignore
74b04a01 48{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-27-if-false/src/main.rs:here}}
13cf67c4
XL
49```
50
51Run the program again, and look at the output:
52
f035d41b 53```console
74b04a01 54{{#include ../listings/ch03-common-programming-concepts/no-listing-27-if-false/output.txt}}
13cf67c4
XL
55```
56
57It’s also worth noting that the condition in this code *must* be a `bool`. If
69743fb6
XL
58the condition isn’t a `bool`, we’ll get an error. For example, try running the
59following code:
13cf67c4
XL
60
61<span class="filename">Filename: src/main.rs</span>
62
63```rust,ignore,does_not_compile
74b04a01 64{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/src/main.rs}}
13cf67c4
XL
65```
66
67The `if` condition evaluates to a value of `3` this time, and Rust throws an
68error:
69
f035d41b 70```console
74b04a01 71{{#include ../listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/output.txt}}
13cf67c4
XL
72```
73
74The error indicates that Rust expected a `bool` but got an integer. Unlike
75languages such as Ruby and JavaScript, Rust will not automatically try to
76convert non-Boolean types to a Boolean. You must be explicit and always provide
77`if` with a Boolean as its condition. If we want the `if` code block to run
78only when a number is not equal to `0`, for example, we can change the `if`
79expression to the following:
80
81<span class="filename">Filename: src/main.rs</span>
82
83```rust
74b04a01 84{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-29-if-not-equal-0/src/main.rs}}
13cf67c4
XL
85```
86
87Running this code will print `number was something other than zero`.
88
89#### Handling Multiple Conditions with `else if`
90
3c0e092e 91You can use multiple conditions by combining `if` and `else` in an `else if`
13cf67c4
XL
92expression. For example:
93
94<span class="filename">Filename: src/main.rs</span>
95
96```rust
74b04a01 97{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-30-else-if/src/main.rs}}
13cf67c4
XL
98```
99
100This program has four possible paths it can take. After running it, you should
101see the following output:
102
f035d41b 103```console
74b04a01 104{{#include ../listings/ch03-common-programming-concepts/no-listing-30-else-if/output.txt}}
13cf67c4
XL
105```
106
107When this program executes, it checks each `if` expression in turn and executes
108the first body for which the condition holds true. Note that even though 6 is
109divisible by 2, we don’t see the output `number is divisible by 2`, nor do we
110see the `number is not divisible by 4, 3, or 2` text from the `else` block.
111That’s because Rust only executes the block for the first true condition, and
112once it finds one, it doesn’t even check the rest.
113
114Using too many `else if` expressions can clutter your code, so if you have more
115than one, you might want to refactor your code. Chapter 6 describes a powerful
116Rust branching construct called `match` for these cases.
117
118#### Using `if` in a `let` Statement
119
120Because `if` is an expression, we can use it on the right side of a `let`
3c0e092e 121statement to assign the outcome to a variable, as in Listing 3-2.
13cf67c4
XL
122
123<span class="filename">Filename: src/main.rs</span>
124
125```rust
74b04a01 126{{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-02/src/main.rs}}
13cf67c4
XL
127```
128
129<span class="caption">Listing 3-2: Assigning the result of an `if` expression
130to a variable</span>
131
132The `number` variable will be bound to a value based on the outcome of the `if`
133expression. Run this code to see what happens:
134
f035d41b 135```console
74b04a01 136{{#include ../listings/ch03-common-programming-concepts/listing-03-02/output.txt}}
13cf67c4
XL
137```
138
139Remember that blocks of code evaluate to the last expression in them, and
140numbers by themselves are also expressions. In this case, the value of the
141whole `if` expression depends on which block of code executes. This means the
142values that have the potential to be results from each arm of the `if` must be
143the same type; in Listing 3-2, the results of both the `if` arm and the `else`
144arm were `i32` integers. If the types are mismatched, as in the following
145example, we’ll get an error:
146
147<span class="filename">Filename: src/main.rs</span>
148
149```rust,ignore,does_not_compile
74b04a01 150{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/src/main.rs}}
13cf67c4
XL
151```
152
69743fb6
XL
153When we try to compile this code, we’ll get an error. The `if` and `else` arms
154have value types that are incompatible, and Rust indicates exactly where to
155find the problem in the program:
13cf67c4 156
f035d41b 157```console
74b04a01 158{{#include ../listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/output.txt}}
13cf67c4
XL
159```
160
161The expression in the `if` block evaluates to an integer, and the expression in
162the `else` block evaluates to a string. This won’t work because variables must
3c0e092e
XL
163have a single type, and Rust needs to know at compile time what type the
164`number` variable is, definitively. Knowing the type of `number` lets the
165compiler verify the type is valid everywhere we use `number`. Rust wouldn’t be
166able to do that if the type of `number` was only determined at runtime; the
167compiler would be more complex and would make fewer guarantees about the code
168if it had to keep track of multiple hypothetical types for any variable.
13cf67c4
XL
169
170### Repetition with Loops
171
172It’s often useful to execute a block of code more than once. For this task,
3c0e092e
XL
173Rust provides several *loops*, which will run through the code inside the loop
174body to the end and then start immediately back at the beginning. To
13cf67c4
XL
175experiment with loops, let’s make a new project called *loops*.
176
177Rust has three kinds of loops: `loop`, `while`, and `for`. Let’s try each one.
178
179#### Repeating Code with `loop`
180
181The `loop` keyword tells Rust to execute a block of code over and over again
182forever or until you explicitly tell it to stop.
183
184As an example, change the *src/main.rs* file in your *loops* directory to look
185like this:
186
187<span class="filename">Filename: src/main.rs</span>
188
189```rust,ignore
74b04a01 190{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-32-loop/src/main.rs}}
13cf67c4
XL
191```
192
193When we run this program, we’ll see `again!` printed over and over continuously
3c0e092e
XL
194until we stop the program manually. Most terminals support the keyboard shortcut
195<span class="keystroke">ctrl-c</span> to interrupt a program that is stuck in
532ac7d7 196a continual loop. Give it a try:
13cf67c4 197
74b04a01
XL
198<!-- manual-regeneration
199cd listings/ch03-common-programming-concepts/no-listing-32-loop
200cargo run
201CTRL-C
202-->
203
f035d41b 204```console
13cf67c4
XL
205$ cargo run
206 Compiling loops v0.1.0 (file:///projects/loops)
74b04a01 207 Finished dev [unoptimized + debuginfo] target(s) in 0.29s
13cf67c4
XL
208 Running `target/debug/loops`
209again!
210again!
211again!
212again!
213^Cagain!
214```
215
216The symbol `^C` represents where you pressed <span class="keystroke">ctrl-c
217</span>. You may or may not see the word `again!` printed after the `^C`,
532ac7d7
XL
218depending on where the code was in the loop when it received the interrupt
219signal.
13cf67c4 220
3c0e092e
XL
221Fortunately, Rust also provides a way to break out of a loop using code. You
222can place the `break` keyword within the loop to tell the program when to stop
94222f64 223executing the loop. Recall that we did this in the guessing game in the
9fa01778
XL
224[“Quitting After a Correct Guess”][quitting-after-a-correct-guess]<!-- ignore
225--> section of Chapter 2 to exit the program when the user won the game by
226guessing the correct number.
13cf67c4 227
3c0e092e
XL
228We also used `continue` in the guessing game, which in a loop tells the program
229to skip over any remaining code in this iteration of the loop and go to the
230next iteration.
94222f64
XL
231
232If you have loops within loops, `break` and `continue` apply to the innermost
3c0e092e
XL
233loop at that point. You can optionally specify a *loop label* on a loop that we
234can then use with `break` or `continue` to specify that those keywords apply to
94222f64
XL
235the labeled loop instead of the innermost loop. Here’s an example with two
236nested loops:
237
238```rust
239{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-32-5-loop-labels/src/main.rs}}
240```
241
242The outer loop has the label `'counting_up`, and it will count up from 0 to 2.
243The inner loop without a label counts down from 10 to 9. The first `break` that
244doesn’t specify a label will exit the inner loop only. The `break
245'counting_up;` statement will exit the outer loop. This code prints:
246
247```console
248{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-32-5-loop-labels/output.txt}}
249```
250
532ac7d7 251#### Returning Values from Loops
13cf67c4 252
532ac7d7 253One of the uses of a `loop` is to retry an operation you know might fail, such
3c0e092e
XL
254as checking whether a thread has completed its job. You might also need to pass
255the result of that operation out of the loop to the rest of your code. To do
256this, you can add the value you want returned after the `break` expression you
257use to stop the loop; that value will be returned out of the loop so you can
258use it, as shown here:
13cf67c4
XL
259
260```rust
74b04a01 261{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-33-return-value-from-loop/src/main.rs}}
13cf67c4
XL
262```
263
9fa01778 264Before the loop, we declare a variable named `counter` and initialize it to
532ac7d7
XL
265`0`. Then we declare a variable named `result` to hold the value returned from
266the loop. On every iteration of the loop, we add `1` to the `counter` variable,
267and then check whether the counter is equal to `10`. When it is, we use the
268`break` keyword with the value `counter * 2`. After the loop, we use a
269semicolon to end the statement that assigns the value to `result`. Finally, we
270print the value in `result`, which in this case is 20.
9fa01778 271
13cf67c4
XL
272#### Conditional Loops with `while`
273
3c0e092e
XL
274A program will often need to evaluate a condition within a loop. While the
275condition is true, the loop runs. When the condition ceases to be true, the
276program calls `break`, stopping the loop. It’s possible to implement behavior
277like this using a combination of `loop`, `if`, `else`, and `break`; you could
278try that now in a program, if you’d like. However, this pattern is so common
279that Rust has a built-in language construct for it, called a `while` loop. In
280Listing 3-3, we use `while` to loop the program three times, counting down each
281time, and then, after the loop, print a message and exit.
13cf67c4
XL
282
283<span class="filename">Filename: src/main.rs</span>
284
285```rust
74b04a01 286{{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-03/src/main.rs}}
13cf67c4
XL
287```
288
289<span class="caption">Listing 3-3: Using a `while` loop to run code while a
290condition holds true</span>
291
292This construct eliminates a lot of nesting that would be necessary if you used
293`loop`, `if`, `else`, and `break`, and it’s clearer. While a condition holds
294true, the code runs; otherwise, it exits the loop.
295
296#### Looping Through a Collection with `for`
297
3c0e092e
XL
298You can choose to use the `while` construct to loop over the elements of a
299collection, such as an array. For example, the loop in Listing 3-4 prints each
300element in the array `a`.
13cf67c4
XL
301
302<span class="filename">Filename: src/main.rs</span>
303
304```rust
74b04a01 305{{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-04/src/main.rs}}
13cf67c4
XL
306```
307
308<span class="caption">Listing 3-4: Looping through each element of a collection
309using a `while` loop</span>
310
311Here, the code counts up through the elements in the array. It starts at index
312`0`, and then loops until it reaches the final index in the array (that is,
313when `index < 5` is no longer true). Running this code will print every element
314in the array:
315
6a06907d 316```console
74b04a01 317{{#include ../listings/ch03-common-programming-concepts/listing-03-04/output.txt}}
13cf67c4
XL
318```
319
320All five array values appear in the terminal, as expected. Even though `index`
321will reach a value of `5` at some point, the loop stops executing before trying
322to fetch a sixth value from the array.
323
3c0e092e
XL
324However, this approach is error prone; we could cause the program to panic if
325the index value or test condition are incorrect. For example, if you changed
326the definition of the `a` array to have four elements but forgot to update the
327condition to `while index < 4`, the code would panic. It’s also slow, because
328the compiler adds runtime code to perform the conditional check of whether the
94222f64 329index is within the bounds of the array on every iteration through the loop.
13cf67c4
XL
330
331As a more concise alternative, you can use a `for` loop and execute some code
69743fb6 332for each item in a collection. A `for` loop looks like the code in Listing 3-5.
13cf67c4
XL
333
334<span class="filename">Filename: src/main.rs</span>
335
336```rust
74b04a01 337{{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-05/src/main.rs}}
13cf67c4
XL
338```
339
340<span class="caption">Listing 3-5: Looping through each element of a collection
341using a `for` loop</span>
342
343When we run this code, we’ll see the same output as in Listing 3-4. More
344importantly, we’ve now increased the safety of the code and eliminated the
345chance of bugs that might result from going beyond the end of the array or not
346going far enough and missing some items.
347
3c0e092e
XL
348Using the `for` loop, you wouldn’t need to remember to change any other code if
349you changed the number of values in the array, as you would with the method
350used in Listing 3-4.
13cf67c4 351
3c0e092e
XL
352The safety and conciseness of `for` loops make them the most commonly used loop
353construct in Rust. Even in situations in which you want to run some code a
354certain number of times, as in the countdown example that used a `while` loop
13cf67c4 355in Listing 3-3, most Rustaceans would use a `for` loop. The way to do that
3c0e092e
XL
356would be to use a `Range`, provided by the standard library, which generates
357all numbers in sequence starting from one number and ending before another
358number.
13cf67c4
XL
359
360Here’s what the countdown would look like using a `for` loop and another method
361we’ve not yet talked about, `rev`, to reverse the range:
362
363<span class="filename">Filename: src/main.rs</span>
364
365```rust
74b04a01 366{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-34-for-range/src/main.rs}}
13cf67c4
XL
367```
368
369This code is a bit nicer, isn’t it?
370
371## Summary
372
373You made it! That was a sizable chapter: you learned about variables, scalar
3c0e092e
XL
374and compound data types, functions, comments, `if` expressions, and loops!
375To practice with the concepts discussed in this chapter, try building
13cf67c4
XL
376programs to do the following:
377
378* Convert temperatures between Fahrenheit and Celsius.
379* Generate the nth Fibonacci number.
380* Print the lyrics to the Christmas carol “The Twelve Days of Christmas,”
69743fb6 381 taking advantage of the repetition in the song.
13cf67c4
XL
382
383When you’re ready to move on, we’ll talk about a concept in Rust that *doesn’t*
384commonly exist in other programming languages: ownership.
9fa01778
XL
385
386[comparing-the-guess-to-the-secret-number]:
387ch02-00-guessing-game-tutorial.html#comparing-the-guess-to-the-secret-number
388[quitting-after-a-correct-guess]:
389ch02-00-guessing-game-tutorial.html#quitting-after-a-correct-guess