]> git.proxmox.com Git - rustc.git/blobdiff - src/doc/book/second-edition/src/ch18-01-all-the-places-for-patterns.md
New upstream version 1.23.0+dfsg1
[rustc.git] / src / doc / book / second-edition / src / ch18-01-all-the-places-for-patterns.md
index 352d2ed17e3f3d5dbba354e921bb5060745c0584..1cc9a90a8c9d6d33697de03c8f28117c50412c56 100644 (file)
@@ -1,15 +1,15 @@
 ## All the Places Patterns May be Used
 
-Patterns pop up in a number of places in Rust. You’ve been using them a lot
+Patterns pop up in a number of places in Rust, and you’ve been using them a lot
 without realizing it! This section is a reference to all the places where
 patterns are valid.
 
 ### `match` Arms
 
-As we discussed in Chapter 6, a common place patterns are used is in the arms
-of `match` expressions. Formally, `match` expressions are defined as the
-keyword `match`, a value to match on, and one or more match arms that consist
-of a pattern and an expression to run if the value matches that arm’s pattern:
+As we discussed in Chapter 6, patterns are used in the arms of `match`
+expressions. Formally, `match` expressions are defined as the keyword `match`,
+a value to match on, and one or more match arms that consist of a pattern and
+an expression to run if the value matches that arm’s pattern:
 
 ```text
 match VALUE {
@@ -19,36 +19,46 @@ match VALUE {
 }
 ```
 
-#### Exhaustiveness and the Default Pattern `_`
-
-`match` expressions are required to be exhaustive. When we put all of the
-patterns in the arms together, all possibilities for the value in the `match`
-expression must be accounted for. One way to ensure you have every possibility
-covered is to have a catch-all pattern for the last arm, like a variable name.
-A name matching any value can never fail and thus covers every case remaining
-after the previous arms’ patterns.
-
-There’s an additional pattern that’s often used in the last match arm: `_`. It
-matches anything, but it never binds any variables. This can be useful when you
-only want to run code for some patterns but ignore any other value, for example.
-
-### `if let` Expressions
-
-We discussed `if let` expressions in Chapter 6, and how they’re mostly a
-shorter way to write the equivalent of a `match` that only cares about matching
-one case. `if let` can optionally have a corresponding `else` with code to run
-if the pattern in the `if let` doesn’t match.
-
-Listing 18-1 shows that it’s even possible to mix and match `if let`, `else
-if`, and `else if let`. This code shows a series of checks of a bunch of
-different conditions to decide what the background color should be. For the
-purposes of the example, we’ve created variables with hardcoded values that a
-real program might get by asking the user. If the user has specified a favorite
-color, we’ll use that as the background color. If today is Tuesday, the
-background color will be green. If the user has specified their age as a string
-and we can parse it as a number successfully, we’ll use either purple or orange
-depending on the value of the parsed number. Finally, if none of these
-conditions apply, the background color will be blue:
+`match` expressions are required to be *exhaustive*, in the sense that all
+possibilities for the value in the `match` expression must be accounted for.
+One way to ensure you have every possibility covered is to have a catch-all
+pattern for the last arm---for example, a variable name matching any value can
+never fail and thus covers every case remaining.
+
+There’s a particular pattern `_` that will match anything, but never binds to a
+variable, and so is often used in the last match arm. This can be useful when
+you want to ignore any value not specified, for example. We’ll cover this in
+more detail later in this chapter.
+
+### Conditional `if let` Expressions
+
+In Chapter 6 we discussed how `if let` expressions are used mainly as a shorter
+way to write the equivalent of a `match` that only cares about matching one
+case. Optionally,`if let` can have a corresponding `else` with code to run if
+the pattern in the `if let` doesn’t match.
+
+<!-- Can you say up front why we'd use this, and not just a match? I've just
+added something here, not sure if it's right -->
+<!-- The first sentence says why-- it's a shorter way to write a `match` when
+there's only one case we care about. Can you elaborate on why that's not clear
+or up front? /Carol -->
+
+Listing 18-1 shows that it’s also possible to mix and match `if let`, `else
+if`, and `else if let` expressions. This gives us more flexibility than a
+`match` expression where we can only express one value to compare with the
+patterns; the conditions in a series of `if let`/`else if`/`else if let` arms
+aren’t required to have any relation to each other.
+
+The code in Listing 18-1 shows a series of checks for a bunch of different
+conditions that decide what the background color should be. For the purposes of
+the example, we’ve created variables with hardcoded values that a real program
+might get by asking the user.
+
+If the user has specified a favorite color, that is used as the background
+color. If today is Tuesday, the background color will be green. If the user has
+specified their age as a string and we can parse it as a number successfully,
+we’ll use either purple or orange depending on the value of the parsed number.
+Finally, if none of these conditions apply, the background color will be blue:
 
 <span class="filename">Filename: src/main.rs</span>
 
@@ -81,26 +91,30 @@ This conditional structure lets us support complex requirements. With the
 hardcoded values we have here, this example will print `Using purple as the
 background color`.
 
-Note that `if let` can also introduce shadowed variables like `match` arms can:
-`if let Ok(age) = age` introduces a new shadowed `age` variable that contains
-the value inside the `Ok` variant. This also means the `if age > 30` condition
-needs to go within the block; we aren’t able to combine these two conditions
-into `if let Ok(age) = age && age > 30` since the shadowed `age` that we want
-to compare to 30 isn’t valid until the new scope starts with the curly bracket.
+We can see that `if let` can also introduce shadowed variables, in the same way
+that `match` arms can: `if let Ok(age) = age` introduces a new shadowed `age`
+variable that contains the value inside the `Ok` variant. This means we need to
+place the `if age > 30` condition within that block; we can’t combine these two
+conditions into `if let Ok(age) = age && age > 30` because the shadowed `age`
+we want to compare to 30 isn’t valid until the new scope starts with the curly
+brace.
 
-Also note that conditionals with many cases like these are not as powerful as
-`match` expression since exhaustiveness is not checked by the compiler. If we
-leave off the last `else` block and miss handling some cases, the compiler will
-not error. This example might be too complex to rewrite as a readable `match`,
-so we should take extra care to check that we’re handling all the cases since
-the compiler is not checking exhaustiveness for us.
+The downside of using `if let` expressions in this way is that exhaustiveness
+is not checked by the compiler, whereas with `match` expressions it is. If we
+left off the last `else` block and so missed handling some cases, the compiler
+would not alert us of the possible logic bug.
 
-### `while let`
+<!-- So what would happen, we'd just end up with a program that wasn't correct,
+in the Rust sense? -->
+<!-- Yes, we would have a logic bug. /Carol -->
 
-A similar construction to `if let` is `while let`: this allows you to do a
-`while` loop as long as a pattern continues to match. Listing 18-2 shows an
-example using a `while let` loop to use a vector as a stack and print out the
-values in the vector in the opposite order that we pushed the values in:
+### `while let` Conditional Loops
+
+Similar in construction to `if let`, the `while let` conditional loop allows
+your `while` loop to run for as long as a pattern continues to match. The
+example in Listing 18-2 shows a `while let` loop that uses a vector as a stack
+and prints out the values in the vector in the opposite order they were pushed
+in:
 
 ```rust
 let mut stack = Vec::new();
@@ -114,23 +128,37 @@ while let Some(top) = stack.pop() {
 }
 ```
 
-<span class="caption">Listing 18-2: Using a `while let` loop to print out values
-as long as `stack.pop()` returns `Some`</span>
+<span class="caption">Listing 18-2: Using a `while let` loop to print out
+values for as long as `stack.pop()` returns `Some`</span>
+
+<!-- Some lovely simple, but edifying, examples in this chapter!-->
 
 This example will print 3, 2, then 1. The `pop` method takes the last element
 out of the vector and returns `Some(value)`. If the vector is empty, it returns
 `None`. The `while` loop will continue running the code in its block as long as
-`pop` is returning `Some`. Once it returns `None`, the `while` loop stops. We
-can use `while let` to pop every element off our stack.
+`pop` is returning `Some`. Once it returns `None`, the loop stops. We can use
+`while let` to pop every element off our stack.
+
+### `for` Loops
+
+In Chapter 3 we mentioned that the `for` loop is the most common loop
+construction in Rust code, but we haven’t yet discussed the pattern that `for`
+takes. In a `for` loop, the pattern is the value that directly follows the
+keyword `for`, so the `x` in `for x in y`.
 
-### `for` loops
+<!-- Can you check the line I added above? I think it'd help to point out the
+pattern section of a for loop straight away -->
+<!-- Yep, looks good! /Carol -->
 
-Looping with `for`, as we discussed in Chapter 3, is the most common loop
-construction in Rust code. What we didn’t talk about in that chapter was that
-`for` takes a pattern. In Listing 18-3, we’re demonstrating how we can use a
-pattern in a `for` loop to destructure a tuple. The `enumerate` method adapts
-an iterator to produce a value and the index of the value in the iterator in a
-tuple:
+Listing 18-3 demonstrates how to use a pattern in a `for` loop to destructure,
+or break apart, a tuple as part of the `for` loop:
+
+<!-- Liz: We've been using the word "destructure" throughout the book in
+chapters 3, 4, 5, and 16. In chapter 3, in the "Grouping Values into Tuples"
+section, we said "This is called *destructuring*, because it breaks the single
+tuple into three parts.". So I don't think we need to define destructure again
+in this chapter, but I've added a small parenthetical here in case the reader
+forgets. /Carol -->
 
 ```rust
 let v = vec![1, 2, 3];
@@ -141,7 +169,7 @@ for (index, value) in v.iter().enumerate() {
 ```
 
 <span class="caption">Listing 18-3: Using a pattern in a `for` loop to
-destructure the tuple returned from `enumerate` into its pieces</span>
+destructure a tuple</span>
 
 This will print:
 
@@ -151,62 +179,94 @@ This will print:
 3 is at index 2
 ```
 
-The first call to `enumerate` produces the tuple `(0, 1)`. When this value is
-matched to the pattern `(index, value)`, `index` will be 0 and `value` will
-be 1.
+We use the `enumerate` method to adapt an iterator to produce a value and that
+value’s index in the iterator, placed into a tuple. The first call to
+`enumerate` produces the tuple `(0, 1)`. When this value is matched to the
+pattern `(index, value)`, `index` will be 0 and `value` will be 1, printing our
+first line of output.
 
 ### `let` Statements
 
-`match` and `if let` are the places we’ve explicitly discussed using patterns
-earlier in the book, but they aren’t the only places we’ve *used* patterns. For
-example, consider this straightforward variable assignment with `let`:
+Before this chapter, we’d only explicitly discussed using patterns with `match`
+and `if let`, but in fact we’ve used patterns in other places too, including
+`let` statements. For example, consider this straightforward variable
+assignment with `let`:
 
 ```rust
 let x = 5;
 ```
 
-We’ve done this hundreds of times throughout this book. You may not have
-realized it, but you were using patterns! A `let` statement looks like this,
+We’ve done this hundreds of times throughout this book, and though you may not
+have realized it, you were using patterns! A `let` statement looks like this,
 more formally:
 
 ```text
 let PATTERN = EXPRESSION;
 ```
 
-We’ve seen statements like `let x = 5;` with a variable name in the `PATTERN`
-slot; a variable name is just a particularly humble form of pattern.
-
-With `let`, we compare the expression against the pattern, and assign any names
-we find. So for example, in our `let x = 5;` case, `x` is a pattern that says
-“bind what matches here to the variable `x`.” And since the name `x` is the
-whole pattern, this pattern effectively means “bind everything to the variable
-`x`, whatever the value is.”
+In statements like `let x = 5;` with a variable name in the `PATTERN` slot, the
+variable name is just a particularly humble form of pattern. We compare the
+expression against the pattern, and assign any names we find. So for our `let x
+= 5;` example, `x` is a pattern that says “bind what matches here to the
+variable `x`.” And since the name `x` is the whole pattern, this pattern
+effectively means “bind everything to the variable `x`, whatever the value is.”
 
 To see the pattern matching aspect of `let` a bit more clearly, consider
-Listing 18-4 where we’re using a pattern with `let` to destructuring a tuple:
+Listing 18-4 where we’re using a pattern with `let` to destructure a tuple:
 
 ```rust
 let (x, y, z) = (1, 2, 3);
 ```
 
 <span class="caption">Listing 18-4: Using a pattern to destructure a tuple and
-create 3 variables at once</span>
+create three variables at once</span>
+
+Here, we match a tuple against a pattern. Rust compares the value `(1, 2, 3)`
+to the pattern `(x, y, z)` and sees that the value matches the pattern, so will
+bind `1` to `x`, `2` to `y`, and `3` to `z`. You can think of this tuple
+pattern as nesting three individual variable patterns inside of it.
+
+<!-- so if we have a pattern of four elements, say (w, x, y, z), but only three
+values, would the values would not bind at all? -->
+<!-- Either too many or too few elements in the pattern is a type error. I've
+added a small example below to illustrate. /Carol -->
 
-Here, we have a tuple that we’re matching against a pattern. Rust will compare
-the value `(1, 2, 3)` to the pattern `(x, y, z)` and see that the value matches
-the pattern. In this case, it will bind `1` to `x`, `2` to `y`, and `3` to `z`.
-You can think of this tuple pattern as nesting three individual variable
-patterns inside of it.
+If the number of elements in the pattern don’t match the number of elements in
+the tuple, the overall type won’t match and we’ll get a compiler error. For
+example, Listing 18-5 shows an attempt to destructure into two variables a
+tuple with three elements that won’t work:
+
+```rust,ignore
+let (x, y) = (1, 2, 3);
+```
+
+<span class="caption">Listing 18-5: Incorrectly constructing a pattern whose
+variables don’t match the number of elements in the tuple</span>
+
+Attempting to compile this code gives us this type error:
+
+```text
+error[E0308]: mismatched types
+ --> src/main.rs:2:9
+  |
+2 |     let (x, y) = (1, 2, 3);
+  |         ^^^^^^ expected a tuple with 3 elements, found one with 2 elements
+  |
+  = note: expected type `({integer}, {integer}, {integer})`
+             found type `(_, _)`
+```
 
-We saw another example of destructuring a tuple in Chapter 16, Listing 16-6,
-where we destructured the return value of `mpsc::channel()` into the `tx`
-(transmitter) and `rx` (receiver) parts.
+If we wanted to ignore one or more of the values in the tuple, we could use `_`
+or `..` as we’ll see in the “Ignoring Values in a Pattern” section. If the
+problem was that we had too many variables in the pattern, the solution would
+be to make the types match by removing variables so that the number of
+variables is equal to the number of elements in the tuple.
 
 ### Function Parameters
 
-Similarly to `let`, function parameters can also be patterns. The code in
-Listing 18-5 declaring a function named `foo` that takes one parameter named
-`x` of type `i32` should look familiar:
+Function parameters can also be patterns. The code in Listing 18-6, declaring a
+function named `foo` that takes one parameter named `x` of type `i32`, should
+by now look familiar:
 
 ```rust
 fn foo(x: i32) {
@@ -214,12 +274,12 @@ fn foo(x: i32) {
 }
 ```
 
-<span class="caption">Listing 18-5: A function signature uses patterns in the
+<span class="caption">Listing 18-6: A function signature uses patterns in the
 parameters</span>
 
-The `x` part is a pattern! In a similar way as we did with `let`, we could
-match a tuple in a function’s arguments. Listing 18-6 shows how we could split
-apart the values in a tuple as part of passing the tuple to a function:
+The `x` part is a pattern! Like we did with `let`, we could match a tuple in a
+function’s arguments to the pattern. Listing 18-7 splits apart the values in a
+tuple as we pass it to a function:
 
 <span class="filename">Filename: src/main.rs</span>
 
@@ -234,16 +294,16 @@ fn main() {
 }
 ```
 
-<span class="caption">Listing 18-6: A function with parameters that destructure
+<span class="caption">Listing 18-7: A function with parameters that destructure
 a tuple</span>
 
-This will print `Current location: (3, 5)`. When we pass the value `&(3, 5)` to
-`print_coordinates`, the values match the pattern `&(x, y)`. `x` gets the value
-3, and `y` gets the value 5.
+This will print `Current location: (3, 5)`. The values `&(3, 5)` match the
+pattern `&(x, y)`, so `x` gets the value 3, and `y` gets the value 5.
 
-Because closures are similar to functions, as we discussed in Chapter 13, we
-can use patterns in closure parameter lists as well.
+We can use patterns in closure parameter lists in the same way, too, because
+closures are similar to functions, as we discussed in Chapter 13.
 
-One difference between the places we can use patterns is that with `for` loops,
-`let`, and in function parameters, the patterns must be *irrefutable*. Let’s
-discuss that next.
+We’ve seen several ways of using patterns now, but patterns do not work the
+same in every place we can use them; in some places, the patterns must be
+*irrefutable*, meaning they must match any value provided. In other
+circumstances, they may be refutable. Let’s discuss that next.