| ## Control Flow |
| |
| The ability to run some code depending on whether a condition is `true` and to |
| run some code repeatedly while a condition is `true` are basic building blocks |
| in most programming languages. The most common constructs that let you control |
| the flow of execution of Rust code are `if` expressions and loops. |
| |
| ### `if` Expressions |
| |
| An `if` expression allows you to branch your code depending on conditions. You |
| provide a condition and then state, “If this condition is met, run this block of |
| code. If the condition is not met, do not run this block of code.” |
| |
| Create a new project called _branches_ in your _projects_ directory to explore |
| the `if` expression. In the _src/main.rs_ file, input the following: |
| |
| <span class="filename">Filename: src/main.rs</span> |
| |
| ```rust |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-26-if-true/src/main.rs}} |
| ``` |
| |
| All `if` expressions start with the keyword `if`, followed by a condition. In |
| this case, the condition checks whether or not the variable `number` has a value |
| less than 5. We place the block of code to execute if the condition is `true` |
| immediately after the condition inside curly brackets. Blocks of code associated |
| with the conditions in `if` expressions are sometimes called _arms_, just like |
| the arms in `match` expressions that we discussed in the |
| [“Comparing |
| the Guess to the Secret Number”][comparing-the-guess-to-the-secret-number]<!-- |
| ignore --> section of Chapter 2. |
| |
| Optionally, we can also include an `else` expression, which we chose to do here, |
| to give the program an alternative block of code to execute should the condition |
| evaluate to `false`. If you don’t provide an `else` expression and the condition |
| is `false`, the program will just skip the `if` block and move on to the next |
| bit of code. |
| |
| Try running this code; you should see the following output: |
| |
| ```console |
| {{#include ../listings/ch03-common-programming-concepts/no-listing-26-if-true/output.txt}} |
| ``` |
| |
| Let’s try changing the value of `number` to a value that makes the condition |
| `false` to see what happens: |
| |
| ```rust,ignore |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-27-if-false/src/main.rs:here}} |
| ``` |
| |
| Run the program again, and look at the output: |
| |
| ```console |
| {{#include ../listings/ch03-common-programming-concepts/no-listing-27-if-false/output.txt}} |
| ``` |
| |
| It’s also worth noting that the condition in this code _must_ be a `bool`. If |
| the condition isn’t a `bool`, we’ll get an error. For example, try running the |
| following code: |
| |
| <span class="filename">Filename: src/main.rs</span> |
| |
| ```rust,ignore,does_not_compile |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/src/main.rs}} |
| ``` |
| |
| The `if` condition evaluates to a value of `3` this time, and Rust throws an |
| error: |
| |
| ```console |
| {{#include ../listings/ch03-common-programming-concepts/no-listing-28-if-condition-must-be-bool/output.txt}} |
| ``` |
| |
| The error indicates that Rust expected a `bool` but got an integer. Unlike |
| languages such as Ruby and JavaScript, Rust will not automatically try to |
| convert non-Boolean types to a Boolean. You must be explicit and always provide |
| `if` with a Boolean as its condition. If we want the `if` code block to run only |
| when a number is not equal to `0`, for example, we can change the `if` |
| expression to the following: |
| |
| <span class="filename">Filename: src/main.rs</span> |
| |
| ```rust |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-29-if-not-equal-0/src/main.rs}} |
| ``` |
| |
| Running this code will print `number was something other than zero`. |
| |
| #### Handling Multiple Conditions with `else if` |
| |
| You can use multiple conditions by combining `if` and `else` in an `else if` |
| expression. For example: |
| |
| <span class="filename">Filename: src/main.rs</span> |
| |
| ```rust |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-30-else-if/src/main.rs}} |
| ``` |
| |
| This program has four possible paths it can take. After running it, you should |
| see the following output: |
| |
| ```console |
| {{#include ../listings/ch03-common-programming-concepts/no-listing-30-else-if/output.txt}} |
| ``` |
| |
| When this program executes, it checks each `if` expression in turn and executes |
| the first body for which the condition evaluates to `true`. Note that even |
| though 6 is divisible by 2, we don’t see the output `number is divisible by 2`, |
| nor do we see the `number is not divisible by 4, 3, or 2` text from the `else` |
| block. That’s because Rust only executes the block for the first `true` |
| condition, and once it finds one, it doesn’t even check the rest. |
| |
| Using too many `else if` expressions can clutter your code, so if you have more |
| than one, you might want to refactor your code. Chapter 6 describes a powerful |
| Rust branching construct called `match` for these cases. |
| |
| #### Using `if` in a `let` Statement |
| |
| Because `if` is an expression, we can use it on the right side of a `let` |
| statement to assign the outcome to a variable, as in Listing 3-2. |
| |
| <Listing number="3-2" file-name="src/main.rs" caption="Assigning the result of an `if` expression to a variable"> |
| |
| ```rust |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-02/src/main.rs}} |
| ``` |
| |
| </Listing> |
| |
| The `number` variable will be bound to a value based on the outcome of the `if` |
| expression. Run this code to see what happens: |
| |
| ```console |
| {{#include ../listings/ch03-common-programming-concepts/listing-03-02/output.txt}} |
| ``` |
| |
| Remember that blocks of code evaluate to the last expression in them, and |
| numbers by themselves are also expressions. In this case, the value of the whole |
| `if` expression depends on which block of code executes. This means the values |
| that have the potential to be results from each arm of the `if` must be the same |
| type; in Listing 3-2, the results of both the `if` arm and the `else` arm were |
| `i32` integers. If the types are mismatched, as in the following example, we’ll |
| get an error: |
| |
| <span class="filename">Filename: src/main.rs</span> |
| |
| ```rust,ignore,does_not_compile |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/src/main.rs}} |
| ``` |
| |
| When we try to compile this code, we’ll get an error. The `if` and `else` arms |
| have value types that are incompatible, and Rust indicates exactly where to find |
| the problem in the program: |
| |
| ```console |
| {{#include ../listings/ch03-common-programming-concepts/no-listing-31-arms-must-return-same-type/output.txt}} |
| ``` |
| |
| The expression in the `if` block evaluates to an integer, and the expression in |
| the `else` block evaluates to a string. This won’t work because variables must |
| have a single type, and Rust needs to know at compile time what type the |
| `number` variable is, definitively. Knowing the type of `number` lets the |
| compiler verify the type is valid everywhere we use `number`. Rust wouldn’t be |
| able to do that if the type of `number` was only determined at runtime; the |
| compiler would be more complex and would make fewer guarantees about the code if |
| it had to keep track of multiple hypothetical types for any variable. |
| |
| ### Repetition with Loops |
| |
| It’s often useful to execute a block of code more than once. For this task, Rust |
| provides several _loops_, which will run through the code inside the loop body |
| to the end and then start immediately back at the beginning. To experiment with |
| loops, let’s make a new project called _loops_. |
| |
| Rust has three kinds of loops: `loop`, `while`, and `for`. Let’s try each one. |
| |
| #### Repeating Code with `loop` |
| |
| The `loop` keyword tells Rust to execute a block of code over and over again |
| forever or until you explicitly tell it to stop. |
| |
| As an example, change the _src/main.rs_ file in your _loops_ directory to look |
| like this: |
| |
| <span class="filename">Filename: src/main.rs</span> |
| |
| ```rust,ignore |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-32-loop/src/main.rs}} |
| ``` |
| |
| When we run this program, we’ll see `again!` printed over and over continuously |
| until we stop the program manually. Most terminals support the keyboard shortcut |
| <kbd>ctrl</kbd>-<kbd>c</kbd> to interrupt a program that is stuck in a continual |
| loop. Give it a try: |
| |
| <!-- manual-regeneration |
| cd listings/ch03-common-programming-concepts/no-listing-32-loop |
| cargo run |
| CTRL-C |
| --> |
| |
| ```console |
| $ cargo run |
| Compiling loops v0.1.0 (file:///projects/loops) |
| Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.08s |
| Running `target/debug/loops` |
| again! |
| again! |
| again! |
| again! |
| ^Cagain! |
| ``` |
| |
| The symbol `^C` represents where you pressed <kbd>ctrl</kbd>-<kbd>c</kbd>. You |
| may or may not see the word `again!` printed after the `^C`, depending on where |
| the code was in the loop when it received the interrupt signal. |
| |
| Fortunately, Rust also provides a way to break out of a loop using code. You can |
| place the `break` keyword within the loop to tell the program when to stop |
| executing the loop. Recall that we did this in the guessing game in the |
| [“Quitting After a Correct Guess”][quitting-after-a-correct-guess]<!-- ignore |
| --> section of Chapter 2 to exit the program when the user won the game by |
| guessing the correct number. |
| |
| We also used `continue` in the guessing game, which in a loop tells the program |
| to skip over any remaining code in this iteration of the loop and go to the next |
| iteration. |
| |
| #### Returning Values from Loops |
| |
| One of the uses of a `loop` is to retry an operation you know might fail, such |
| as checking whether a thread has completed its job. You might also need to pass |
| the result of that operation out of the loop to the rest of your code. To do |
| this, you can add the value you want returned after the `break` expression you |
| use to stop the loop; that value will be returned out of the loop so you can use |
| it, as shown here: |
| |
| ```rust |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-33-return-value-from-loop/src/main.rs}} |
| ``` |
| |
| Before the loop, we declare a variable named `counter` and initialize it to `0`. |
| Then we declare a variable named `result` to hold the value returned from the |
| loop. On every iteration of the loop, we add `1` to the `counter` variable, and |
| then check whether the `counter` is equal to `10`. When it is, we use the |
| `break` keyword with the value `counter * 2`. After the loop, we use a semicolon |
| to end the statement that assigns the value to `result`. Finally, we print the |
| value in `result`, which in this case is `20`. |
| |
| You can also `return` from inside a loop. While `break` only exits the current |
| loop, `return` always exits the current function. |
| |
| #### Loop Labels to Disambiguate Between Multiple Loops |
| |
| If you have loops within loops, `break` and `continue` apply to the innermost |
| loop at that point. You can optionally specify a _loop label_ on a loop that you |
| can then use with `break` or `continue` to specify that those keywords apply to |
| the labeled loop instead of the innermost loop. Loop labels must begin with a |
| single quote. Here’s an example with two nested loops: |
| |
| ```rust |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-32-5-loop-labels/src/main.rs}} |
| ``` |
| |
| The outer loop has the label `'counting_up`, and it will count up from 0 to 2. |
| The inner loop without a label counts down from 10 to 9. The first `break` that |
| doesn’t specify a label will exit the inner loop only. The `break |
| 'counting_up;` |
| statement will exit the outer loop. This code prints: |
| |
| ```console |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-32-5-loop-labels/output.txt}} |
| ``` |
| |
| #### Conditional Loops with `while` |
| |
| A program will often need to evaluate a condition within a loop. While the |
| condition is `true`, the loop runs. When the condition ceases to be `true`, the |
| program calls `break`, stopping the loop. It’s possible to implement behavior |
| like this using a combination of `loop`, `if`, `else`, and `break`; you could |
| try that now in a program, if you’d like. However, this pattern is so common |
| that Rust has a built-in language construct for it, called a `while` loop. In |
| Listing 3-3, we use `while` to loop the program three times, counting down each |
| time, and then, after the loop, print a message and exit. |
| |
| <Listing number="3-3" file-name="src/main.rs" caption="Using a `while` loop to run code while a condition holds true"> |
| |
| ```rust |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-03/src/main.rs}} |
| ``` |
| |
| </Listing> |
| |
| This construct eliminates a lot of nesting that would be necessary if you used |
| `loop`, `if`, `else`, and `break`, and it’s clearer. While a condition evaluates |
| to `true`, the code runs; otherwise, it exits the loop. |
| |
| #### Looping Through a Collection with `for` |
| |
| You can also use the `while` construct to loop over the elements of a |
| collection, such as an array. For example, the loop in Listing 3-4 prints each |
| element in the array `a`. |
| |
| <Listing number="3-4" file-name="src/main.rs" caption="Looping through each element of a collection using a `while` loop"> |
| |
| ```rust |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-04/src/main.rs}} |
| ``` |
| |
| </Listing> |
| |
| Here, the code counts up through the elements in the array. It starts at index |
| `0`, and then loops until it reaches the final index in the array (that is, when |
| `index < 5` is no longer `true`). Running this code will print every element in |
| the array: |
| |
| ```console |
| {{#include ../listings/ch03-common-programming-concepts/listing-03-04/output.txt}} |
| ``` |
| |
| All five array values appear in the terminal, as expected. Even though `index` |
| will reach a value of `5` at some point, the loop stops executing before trying |
| to fetch a sixth value from the array. |
| |
| However, this approach is error prone; we could cause the program to panic if |
| the index value or test condition is incorrect. For example, if you changed the |
| definition of the `a` array to have four elements but forgot to update the |
| condition to `while index < 4`, the code would panic. It’s also slow, because |
| the compiler adds runtime code to perform the conditional check of whether the |
| index is within the bounds of the array on every iteration through the loop. |
| |
| As a more concise alternative, you can use a `for` loop and execute some code |
| for each item in a collection. A `for` loop looks like the code in Listing 3-5. |
| |
| <Listing number="3-5" file-name="src/main.rs" caption="Looping through each element of a collection using a `for` loop"> |
| |
| ```rust |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/listing-03-05/src/main.rs}} |
| ``` |
| |
| </Listing> |
| |
| When we run this code, we’ll see the same output as in Listing 3-4. More |
| importantly, we’ve now increased the safety of the code and eliminated the |
| chance of bugs that might result from going beyond the end of the array or not |
| going far enough and missing some items. |
| |
| Using the `for` loop, you wouldn’t need to remember to change any other code if |
| you changed the number of values in the array, as you would with the method used |
| in Listing 3-4. |
| |
| The safety and conciseness of `for` loops make them the most commonly used loop |
| construct in Rust. Even in situations in which you want to run some code a |
| certain number of times, as in the countdown example that used a `while` loop in |
| Listing 3-3, most Rustaceans would use a `for` loop. The way to do that would be |
| to use a `Range`, provided by the standard library, which generates all numbers |
| in sequence starting from one number and ending before another number. |
| |
| Here’s what the countdown would look like using a `for` loop and another method |
| we’ve not yet talked about, `rev`, to reverse the range: |
| |
| <span class="filename">Filename: src/main.rs</span> |
| |
| ```rust |
| {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-34-for-range/src/main.rs}} |
| ``` |
| |
| This code is a bit nicer, isn’t it? |
| |
| ## Summary |
| |
| You made it! This was a sizable chapter: you learned about variables, scalar and |
| compound data types, functions, comments, `if` expressions, and loops! To |
| practice with the concepts discussed in this chapter, try building programs to |
| do the following: |
| |
| * Convert temperatures between Fahrenheit and Celsius. |
| * Generate the *n*th Fibonacci number. |
| * Print the lyrics to the Christmas carol “The Twelve Days of Christmas,” taking |
| advantage of the repetition in the song. |
| |
| When you’re ready to move on, we’ll talk about a concept in Rust that _doesn’t_ |
| commonly exist in other programming languages: ownership. |
| |
| [comparing-the-guess-to-the-secret-number]: ch02-00-guessing-game-tutorial.html#comparing-the-guess-to-the-secret-number |
| [quitting-after-a-correct-guess]: ch02-00-guessing-game-tutorial.html#quitting-after-a-correct-guess |