]> git.proxmox.com Git - rustc.git/blame - src/doc/book/src/ch03-05-control-flow.md
New upstream version 1.62.1+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
5e7ed085 25value less than 5. We place the block of code to execute if the condition is true
3c0e092e
XL
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 231
532ac7d7 232#### Returning Values from Loops
13cf67c4 233
532ac7d7 234One of the uses of a `loop` is to retry an operation you know might fail, such
3c0e092e
XL
235as checking whether a thread has completed its job. You might also need to pass
236the result of that operation out of the loop to the rest of your code. To do
237this, you can add the value you want returned after the `break` expression you
238use to stop the loop; that value will be returned out of the loop so you can
239use it, as shown here:
13cf67c4
XL
240
241```rust
74b04a01 242{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-33-return-value-from-loop/src/main.rs}}
13cf67c4
XL
243```
244
9fa01778 245Before the loop, we declare a variable named `counter` and initialize it to
532ac7d7
XL
246`0`. Then we declare a variable named `result` to hold the value returned from
247the loop. On every iteration of the loop, we add `1` to the `counter` variable,
248and then check whether the counter is equal to `10`. When it is, we use the
249`break` keyword with the value `counter * 2`. After the loop, we use a
250semicolon to end the statement that assigns the value to `result`. Finally, we
251print the value in `result`, which in this case is 20.
9fa01778 252
04454e1e
FG
253#### Loop Labels to Disambiguate Between Multiple Loops
254
255If you have loops within loops, `break` and `continue` apply to the innermost
256loop at that point. You can optionally specify a *loop label* on a loop that we
257can then use with `break` or `continue` to specify that those keywords apply to
258the labeled loop instead of the innermost loop. Loop labels must begin with a
259single quote. Here’s an example with two nested loops:
260
261```rust
262{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-32-5-loop-labels/src/main.rs}}
263```
264
265The outer loop has the label `'counting_up`, and it will count up from 0 to 2.
266The inner loop without a label counts down from 10 to 9. The first `break` that
267doesn’t specify a label will exit the inner loop only. The `break
268'counting_up;` statement will exit the outer loop. This code prints:
269
270```console
271{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-32-5-loop-labels/output.txt}}
272```
273
13cf67c4
XL
274#### Conditional Loops with `while`
275
3c0e092e
XL
276A program will often need to evaluate a condition within a loop. While the
277condition is true, the loop runs. When the condition ceases to be true, the
278program calls `break`, stopping the loop. It’s possible to implement behavior
279like this using a combination of `loop`, `if`, `else`, and `break`; you could
280try that now in a program, if you’d like. However, this pattern is so common
281that Rust has a built-in language construct for it, called a `while` loop. In
282Listing 3-3, we use `while` to loop the program three times, counting down each
283time, and then, after the loop, print a message and exit.
13cf67c4
XL
284
285<span class="filename">Filename: src/main.rs</span>
286
287```rust
74b04a01 288{{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-03/src/main.rs}}
13cf67c4
XL
289```
290
291<span class="caption">Listing 3-3: Using a `while` loop to run code while a
292condition holds true</span>
293
294This construct eliminates a lot of nesting that would be necessary if you used
295`loop`, `if`, `else`, and `break`, and it’s clearer. While a condition holds
296true, the code runs; otherwise, it exits the loop.
297
298#### Looping Through a Collection with `for`
299
3c0e092e
XL
300You can choose to use the `while` construct to loop over the elements of a
301collection, such as an array. For example, the loop in Listing 3-4 prints each
302element in the array `a`.
13cf67c4
XL
303
304<span class="filename">Filename: src/main.rs</span>
305
306```rust
74b04a01 307{{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-04/src/main.rs}}
13cf67c4
XL
308```
309
310<span class="caption">Listing 3-4: Looping through each element of a collection
311using a `while` loop</span>
312
313Here, the code counts up through the elements in the array. It starts at index
314`0`, and then loops until it reaches the final index in the array (that is,
315when `index < 5` is no longer true). Running this code will print every element
316in the array:
317
6a06907d 318```console
74b04a01 319{{#include ../listings/ch03-common-programming-concepts/listing-03-04/output.txt}}
13cf67c4
XL
320```
321
322All five array values appear in the terminal, as expected. Even though `index`
323will reach a value of `5` at some point, the loop stops executing before trying
324to fetch a sixth value from the array.
325
3c0e092e
XL
326However, this approach is error prone; we could cause the program to panic if
327the index value or test condition are incorrect. For example, if you changed
328the definition of the `a` array to have four elements but forgot to update the
329condition to `while index < 4`, the code would panic. It’s also slow, because
330the compiler adds runtime code to perform the conditional check of whether the
94222f64 331index is within the bounds of the array on every iteration through the loop.
13cf67c4
XL
332
333As a more concise alternative, you can use a `for` loop and execute some code
69743fb6 334for each item in a collection. A `for` loop looks like the code in Listing 3-5.
13cf67c4
XL
335
336<span class="filename">Filename: src/main.rs</span>
337
338```rust
74b04a01 339{{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-05/src/main.rs}}
13cf67c4
XL
340```
341
342<span class="caption">Listing 3-5: Looping through each element of a collection
343using a `for` loop</span>
344
345When we run this code, we’ll see the same output as in Listing 3-4. More
346importantly, we’ve now increased the safety of the code and eliminated the
347chance of bugs that might result from going beyond the end of the array or not
348going far enough and missing some items.
349
3c0e092e
XL
350Using the `for` loop, you wouldn’t need to remember to change any other code if
351you changed the number of values in the array, as you would with the method
352used in Listing 3-4.
13cf67c4 353
3c0e092e
XL
354The safety and conciseness of `for` loops make them the most commonly used loop
355construct in Rust. Even in situations in which you want to run some code a
356certain number of times, as in the countdown example that used a `while` loop
13cf67c4 357in Listing 3-3, most Rustaceans would use a `for` loop. The way to do that
3c0e092e
XL
358would be to use a `Range`, provided by the standard library, which generates
359all numbers in sequence starting from one number and ending before another
360number.
13cf67c4
XL
361
362Here’s what the countdown would look like using a `for` loop and another method
363we’ve not yet talked about, `rev`, to reverse the range:
364
365<span class="filename">Filename: src/main.rs</span>
366
367```rust
74b04a01 368{{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-34-for-range/src/main.rs}}
13cf67c4
XL
369```
370
371This code is a bit nicer, isn’t it?
372
373## Summary
374
375You made it! That was a sizable chapter: you learned about variables, scalar
3c0e092e
XL
376and compound data types, functions, comments, `if` expressions, and loops!
377To practice with the concepts discussed in this chapter, try building
13cf67c4
XL
378programs to do the following:
379
380* Convert temperatures between Fahrenheit and Celsius.
381* Generate the nth Fibonacci number.
382* Print the lyrics to the Christmas carol “The Twelve Days of Christmas,”
69743fb6 383 taking advantage of the repetition in the song.
13cf67c4
XL
384
385When you’re ready to move on, we’ll talk about a concept in Rust that *doesn’t*
386commonly exist in other programming languages: ownership.
9fa01778
XL
387
388[comparing-the-guess-to-the-secret-number]:
389ch02-00-guessing-game-tutorial.html#comparing-the-guess-to-the-secret-number
390[quitting-after-a-correct-guess]:
391ch02-00-guessing-game-tutorial.html#quitting-after-a-correct-guess