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