3 Deciding whether or not to run some code depending on if a condition is true or
4 deciding to run some code repeatedly while a condition is true are basic
5 building blocks in most programming languages. The most common constructs that
6 let you control the flow of execution of Rust code are `if` expressions and
11 An `if` expression allows us to branch our code depending on conditions. We
12 provide a condition and then state, “If this condition is met, run this block
13 of code. If the condition is not met, do not run this block of code.”
15 Create a new project called *branches* in your *projects* directory to explore
16 the `if` expression. In the *src/main.rs* file, input the following:
18 <span class="filename">Filename: src/main.rs</span>
25 println!("condition was true");
27 println!("condition was false");
32 <!-- NEXT PARAGRAPH WRAPPED WEIRD INTENTIONALLY SEE #199 -->
34 All `if` expressions start with the keyword `if`, which is followed by a
35 condition. In this case, the condition checks whether or not the variable
36 `number` has a value less than 5. The block of code we want to execute if the
37 condition is true is placed immediately after the condition inside curly
38 brackets. Blocks of code associated with the conditions in `if` expressions are
39 sometimes called *arms*, just like the arms in `match` expressions that we
40 discussed in the “Comparing the Guess to the Secret Number” section of
41 Chapter 2. Optionally, we can also include an `else` expression, which we chose
42 to do here, to give the program an alternative block of code to execute should
43 the condition evaluate to false. If you don’t provide an `else` expression and
44 the condition is false, the program will just skip the `if` block and move on
45 to the next bit of code.
47 Try running this code; you should see the following output:
51 Compiling branches v0.1.0 (file:///projects/branches)
52 Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
53 Running `target/debug/branches`
57 Let’s try changing the value of `number` to a value that makes the condition
58 `false` to see what happens:
64 Run the program again, and look at the output:
68 Compiling branches v0.1.0 (file:///projects/branches)
69 Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
70 Running `target/debug/branches`
74 It’s also worth noting that the condition in this code *must* be a `bool`. If
75 the condition isn’t a `bool`, we’ll get an error. For example, try running the
78 <span class="filename">Filename: src/main.rs</span>
85 println!("number was three");
90 The `if` condition evaluates to a value of `3` this time, and Rust throws an
94 error[E0308]: mismatched types
98 | ^^^^^^ expected bool, found integral variable
100 = note: expected type `bool`
101 found type `{integer}`
104 The error indicates that Rust expected a `bool` but got an integer. Rust will
105 not automatically try to convert non-boolean types to a boolean, unlike
106 languages such as Ruby and JavaScript. You must be explicit and always provide
107 `if` with a `boolean` as its condition. If we want the `if` code block to run
108 only when a number is not equal to `0`, for example, we can change the `if`
109 expression to the following:
111 <span class="filename">Filename: src/main.rs</span>
118 println!("number was something other than zero");
123 Running this code will print `number was something other than zero`.
125 #### Multiple Conditions with `else if`
127 We can have multiple conditions by combining `if` and `else` in an `else if`
128 expression. For example:
130 <span class="filename">Filename: src/main.rs</span>
137 println!("number is divisible by 4");
138 } else if number % 3 == 0 {
139 println!("number is divisible by 3");
140 } else if number % 2 == 0 {
141 println!("number is divisible by 2");
143 println!("number is not divisible by 4, 3, or 2");
148 This program has four possible paths it can take. After running it, you should
149 see the following output:
153 Compiling branches v0.1.0 (file:///projects/branches)
154 Finished dev [unoptimized + debuginfo] target(s) in 0.31 secs
155 Running `target/debug/branches`
156 number is divisible by 3
159 When this program executes, it checks each `if` expression in turn and executes
160 the first body for which the condition holds true. Note that even though 6 is
161 divisible by 2, we don’t see the output `number is divisible by 2`, nor do we
162 see the `number is not divisible by 4, 3, or 2` text from the `else` block. The
163 reason is that Rust will only execute the block for the first true condition,
164 and once it finds one, it won’t even check the rest.
166 Using too many `else if` expressions can clutter your code, so if you have more
167 than one, you might want to refactor your code. Chapter 6 describes a powerful
168 Rust branching construct called `match` for these cases.
170 #### Using `if` in a `let` statement
172 Because `if` is an expression, we can use it on the right side of a `let`
173 statement, for instance in Listing 3-2:
175 <span class="filename">Filename: src/main.rs</span>
179 let condition = true;
180 let number = if condition {
186 println!("The value of number is: {}", number);
190 <span class="caption">Listing 3-2: Assigning the result of an `if` expression
193 The `number` variable will be bound to a value based on the outcome of the `if`
194 expression. Run this code to see what happens:
198 Compiling branches v0.1.0 (file:///projects/branches)
199 Finished dev [unoptimized + debuginfo] target(s) in 0.30 secs
200 Running `target/debug/branches`
201 The value of number is: 5
204 Remember that blocks of code evaluate to the last expression in them, and
205 numbers by themselves are also expressions. In this case, the value of the
206 whole `if` expression depends on which block of code executes. This means the
207 values that have the potential to be results from each arm of the `if` must be
208 the same type; in Listing 3-2, the results of both the `if` arm and the `else`
209 arm were `i32` integers. If the types are mismatched, as in the following
210 example, we’ll get an error:
212 <span class="filename">Filename: src/main.rs</span>
216 let condition = true;
218 let number = if condition {
224 println!("The value of number is: {}", number);
228 When we try to run this code, we’ll get an error. The `if` and `else` arms have
229 value types that are incompatible, and Rust indicates exactly where to find the
230 problem in the program:
233 error[E0308]: if and else have incompatible types
236 4 | let number = if condition {
237 | __________________^
242 | |_____^ expected integral variable, found reference
244 = note: expected type `{integer}`
248 The expression in the `if` block evaluates to an integer, and the expression in
249 the `else` block evaluates to a string. This won’t work because variables must
250 have a single type. Rust needs to know at compile time what type the `number`
251 variable is, definitively, so it can verify at compile time that its type is
252 valid everywhere we use `number`. Rust wouldn’t be able to do that if the type
253 of `number` was only determined at runtime; the compiler would be more complex
254 and would make fewer guarantees about the code if it had to keep track of
255 multiple hypothetical types for any variable.
257 ### Repetition with Loops
259 It’s often useful to execute a block of code more than once. For this task,
260 Rust provides several *loops*. A loop runs through the code inside the loop
261 body to the end and then starts immediately back at the beginning. To
262 experiment with loops, let’s make a new project called *loops*.
264 Rust has three kinds of loops: `loop`, `while`, and `for`. Let’s try each one.
266 #### Repeating Code with `loop`
268 The `loop` keyword tells Rust to execute a block of code over and over again
269 forever or until you explicitly tell it to stop.
271 As an example, change the *src/main.rs* file in your *loops* directory to look
274 <span class="filename">Filename: src/main.rs</span>
284 When we run this program, we’ll see `again!` printed over and over continuously
285 until we stop the program manually. Most terminals support a keyboard shortcut,
286 <span class="keystroke">ctrl-C</span>, to halt a program that is stuck in a
287 continual loop. Give it a try:
291 Compiling loops v0.1.0 (file:///projects/loops)
292 Finished dev [unoptimized + debuginfo] target(s) in 0.29 secs
293 Running `target/debug/loops`
301 The symbol `^C` represents where you pressed <span class="keystroke">ctrl-C
302 </span>. You may or may not see the word `again!` printed after the `^C`,
303 depending on where the code was in the loop when it received the halt signal.
305 Fortunately, Rust provides another, more reliable way to break out of a loop.
306 You can place the `break` keyword within the loop to tell the program when to
307 stop executing the loop. Recall that we did this in the guessing game in the
308 “Quitting After a Correct Guess” section of Chapter 2 to exit the
309 program when the user won the game by guessing the correct number.
311 #### Conditional Loops with `while`
313 It’s often useful for a program to evaluate a condition within a loop. While
314 the condition is true, the loop runs. When the condition ceases to be true, you
315 call `break`, stopping the loop. This loop type could be implemented using a
316 combination of `loop`, `if`, `else`, and `break`; you could try that now in a
317 program, if you’d like.
319 However, this pattern is so common that Rust has a built-in language construct
320 for it, and it’s called a `while` loop. The following example uses `while`: the
321 program loops three times, counting down each time. Then, after the loop, it
322 prints another message and exits:
324 <span class="filename">Filename: src/main.rs</span>
331 println!("{}!", number);
336 println!("LIFTOFF!!!");
340 This construct eliminates a lot of nesting that would be necessary if you used
341 `loop`, `if`, `else`, and `break`, and it’s clearer. While a condition holds
342 true, the code runs; otherwise, it exits the loop.
344 #### Looping Through a Collection with `for`
346 You could use the `while` construct to loop over the elements of a collection,
347 such as an array. For example, let’s look at Listing 3-3:
349 <span class="filename">Filename: src/main.rs</span>
353 let a = [10, 20, 30, 40, 50];
357 println!("the value is: {}", a[index]);
364 <span class="caption">Listing 3-3: Looping through each element of a collection
365 using a `while` loop</span>
367 Here, the code counts up through the elements in the array. It starts at index
368 `0`, and then loops until it reaches the final index in the array (that is,
369 when `index < 5` is no longer true). Running this code will print out every
370 element in the array:
374 Compiling loops v0.1.0 (file:///projects/loops)
375 Finished dev [unoptimized + debuginfo] target(s) in 0.32 secs
376 Running `target/debug/loops`
384 All five array values appear in the terminal, as expected. Even though `index`
385 will reach a value of `5` at some point, the loop stops executing before trying
386 to fetch a sixth value from the array.
388 But this approach is error prone; we could cause the program to panic if the
389 index length is incorrect. It’s also slow, because the compiler adds runtime
390 code to perform the conditional check on every element on every iteration
393 As a more concise alternative, you can use a `for` loop and execute some code
394 for each item in a collection. A `for` loop looks like this code in Listing 3-4:
396 <span class="filename">Filename: src/main.rs</span>
400 let a = [10, 20, 30, 40, 50];
402 for element in a.iter() {
403 println!("the value is: {}", element);
408 <span class="caption">Listing 3-4: Looping through each element of a collection
409 using a `for` loop</span>
411 When we run this code, we’ll see the same output as in Listing 3-3. More
412 importantly, we’ve now increased the safety of the code and eliminated the
413 chance of bugs that might result from going beyond the end of the array or not
414 going far enough and missing some items.
416 For example, in the code in Listing 3-3, if you removed an item from the `a`
417 array but forgot to update the condition to `while index < 4`, the code would
418 panic. Using the `for` loop, you don’t need to remember to change any other
419 code if you changed the number of values in the array.
421 The safety and conciseness of `for` loops make them the most commonly used loop
422 construct in Rust. Even in situations in which you want to run some code a
423 certain number of times, as in the countdown example that used a `while` loop
424 in Listing 3-3, most Rustaceans would use a `for` loop. The way to do that
425 would be to use a `Range`, which is a type provided by the standard library
426 that generates all numbers in sequence starting from one number and ending
427 before another number.
429 Here’s what the countdown would look like using a `for` loop and another method
430 we’ve not yet talked about, `rev`, to reverse the range:
432 <span class="filename">Filename: src/main.rs</span>
436 for number in (1..4).rev() {
437 println!("{}!", number);
439 println!("LIFTOFF!!!");
443 This code is a bit nicer, isn’t it?
447 You made it! That was a sizable chapter: you learned about variables, scalar
448 and `if` expressions, and loops! If you want to practice with the concepts
449 discussed in this chapter, try building programs to do the following:
451 * Convert temperatures between Fahrenheit and Celsius.
452 * Generate the nth Fibonacci number.
453 * Print the lyrics to the Christmas carol “The Twelve Days of Christmas,”
454 taking advantage of the repetition in the song.
456 When you’re ready to move on, we’ll talk about a concept in Rust that *doesn’t*
457 commonly exist in other programming languages: ownership.