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