]>
Commit | Line | Data |
---|---|---|
cc61c64b XL |
1 | ## All the Places Patterns May be Used |
2 | ||
abe05a73 | 3 | Patterns pop up in a number of places in Rust, and you’ve been using them a lot |
cc61c64b XL |
4 | without realizing it! This section is a reference to all the places where |
5 | patterns are valid. | |
6 | ||
7 | ### `match` Arms | |
8 | ||
abe05a73 XL |
9 | As we discussed in Chapter 6, patterns are used in the arms of `match` |
10 | expressions. Formally, `match` expressions are defined as the keyword `match`, | |
11 | a value to match on, and one or more match arms that consist of a pattern and | |
12 | an expression to run if the value matches that arm’s pattern: | |
cc61c64b XL |
13 | |
14 | ```text | |
15 | match VALUE { | |
16 | PATTERN => EXPRESSION, | |
17 | PATTERN => EXPRESSION, | |
18 | PATTERN => EXPRESSION, | |
19 | } | |
20 | ``` | |
21 | ||
abe05a73 XL |
22 | `match` expressions are required to be *exhaustive*, in the sense that all |
23 | possibilities for the value in the `match` expression must be accounted for. | |
24 | One way to ensure you have every possibility covered is to have a catch-all | |
25 | pattern for the last arm---for example, a variable name matching any value can | |
26 | never fail and thus covers every case remaining. | |
27 | ||
28 | There’s a particular pattern `_` that will match anything, but never binds to a | |
29 | variable, and so is often used in the last match arm. This can be useful when | |
30 | you want to ignore any value not specified, for example. We’ll cover this in | |
31 | more detail later in this chapter. | |
32 | ||
33 | ### Conditional `if let` Expressions | |
34 | ||
35 | In Chapter 6 we discussed how `if let` expressions are used mainly as a shorter | |
36 | way to write the equivalent of a `match` that only cares about matching one | |
37 | case. Optionally,`if let` can have a corresponding `else` with code to run if | |
38 | the pattern in the `if let` doesn’t match. | |
39 | ||
40 | <!-- Can you say up front why we'd use this, and not just a match? I've just | |
41 | added something here, not sure if it's right --> | |
42 | <!-- The first sentence says why-- it's a shorter way to write a `match` when | |
43 | there's only one case we care about. Can you elaborate on why that's not clear | |
44 | or up front? /Carol --> | |
45 | ||
46 | Listing 18-1 shows that it’s also possible to mix and match `if let`, `else | |
47 | if`, and `else if let` expressions. This gives us more flexibility than a | |
48 | `match` expression where we can only express one value to compare with the | |
49 | patterns; the conditions in a series of `if let`/`else if`/`else if let` arms | |
50 | aren’t required to have any relation to each other. | |
51 | ||
52 | The code in Listing 18-1 shows a series of checks for a bunch of different | |
53 | conditions that decide what the background color should be. For the purposes of | |
54 | the example, we’ve created variables with hardcoded values that a real program | |
55 | might get by asking the user. | |
56 | ||
57 | If the user has specified a favorite color, that is used as the background | |
58 | color. If today is Tuesday, the background color will be green. If the user has | |
59 | specified their age as a string and we can parse it as a number successfully, | |
60 | we’ll use either purple or orange depending on the value of the parsed number. | |
61 | Finally, if none of these conditions apply, the background color will be blue: | |
cc61c64b XL |
62 | |
63 | <span class="filename">Filename: src/main.rs</span> | |
64 | ||
65 | ```rust | |
66 | fn main() { | |
67 | let favorite_color: Option<&str> = None; | |
68 | let is_tuesday = false; | |
69 | let age: Result<u8, _> = "34".parse(); | |
70 | ||
71 | if let Some(color) = favorite_color { | |
72 | println!("Using your favorite color, {}, as the background", color); | |
73 | } else if is_tuesday { | |
74 | println!("Tuesday is green day!"); | |
75 | } else if let Ok(age) = age { | |
76 | if age > 30 { | |
77 | println!("Using purple as the background color"); | |
78 | } else { | |
79 | println!("Using orange as the background color"); | |
80 | } | |
81 | } else { | |
82 | println!("Using blue as the background color"); | |
83 | } | |
84 | } | |
85 | ``` | |
86 | ||
87 | <span class="caption">Listing 18-1: Mixing `if let`, `else if`, `else if let`, | |
88 | and `else`</span> | |
89 | ||
90 | This conditional structure lets us support complex requirements. With the | |
91 | hardcoded values we have here, this example will print `Using purple as the | |
92 | background color`. | |
93 | ||
abe05a73 XL |
94 | We can see that `if let` can also introduce shadowed variables, in the same way |
95 | that `match` arms can: `if let Ok(age) = age` introduces a new shadowed `age` | |
96 | variable that contains the value inside the `Ok` variant. This means we need to | |
97 | place the `if age > 30` condition within that block; we can’t combine these two | |
98 | conditions into `if let Ok(age) = age && age > 30` because the shadowed `age` | |
99 | we want to compare to 30 isn’t valid until the new scope starts with the curly | |
100 | brace. | |
cc61c64b | 101 | |
abe05a73 XL |
102 | The downside of using `if let` expressions in this way is that exhaustiveness |
103 | is not checked by the compiler, whereas with `match` expressions it is. If we | |
104 | left off the last `else` block and so missed handling some cases, the compiler | |
105 | would not alert us of the possible logic bug. | |
cc61c64b | 106 | |
abe05a73 XL |
107 | <!-- So what would happen, we'd just end up with a program that wasn't correct, |
108 | in the Rust sense? --> | |
109 | <!-- Yes, we would have a logic bug. /Carol --> | |
cc61c64b | 110 | |
abe05a73 XL |
111 | ### `while let` Conditional Loops |
112 | ||
113 | Similar in construction to `if let`, the `while let` conditional loop allows | |
114 | your `while` loop to run for as long as a pattern continues to match. The | |
115 | example in Listing 18-2 shows a `while let` loop that uses a vector as a stack | |
116 | and prints out the values in the vector in the opposite order they were pushed | |
117 | in: | |
cc61c64b XL |
118 | |
119 | ```rust | |
120 | let mut stack = Vec::new(); | |
121 | ||
122 | stack.push(1); | |
123 | stack.push(2); | |
124 | stack.push(3); | |
125 | ||
126 | while let Some(top) = stack.pop() { | |
127 | println!("{}", top); | |
128 | } | |
129 | ``` | |
130 | ||
abe05a73 XL |
131 | <span class="caption">Listing 18-2: Using a `while let` loop to print out |
132 | values for as long as `stack.pop()` returns `Some`</span> | |
133 | ||
134 | <!-- Some lovely simple, but edifying, examples in this chapter!--> | |
cc61c64b XL |
135 | |
136 | This example will print 3, 2, then 1. The `pop` method takes the last element | |
137 | out of the vector and returns `Some(value)`. If the vector is empty, it returns | |
138 | `None`. The `while` loop will continue running the code in its block as long as | |
abe05a73 XL |
139 | `pop` is returning `Some`. Once it returns `None`, the loop stops. We can use |
140 | `while let` to pop every element off our stack. | |
141 | ||
142 | ### `for` Loops | |
143 | ||
144 | In Chapter 3 we mentioned that the `for` loop is the most common loop | |
145 | construction in Rust code, but we haven’t yet discussed the pattern that `for` | |
146 | takes. In a `for` loop, the pattern is the value that directly follows the | |
147 | keyword `for`, so the `x` in `for x in y`. | |
cc61c64b | 148 | |
abe05a73 XL |
149 | <!-- Can you check the line I added above? I think it'd help to point out the |
150 | pattern section of a for loop straight away --> | |
151 | <!-- Yep, looks good! /Carol --> | |
cc61c64b | 152 | |
abe05a73 XL |
153 | Listing 18-3 demonstrates how to use a pattern in a `for` loop to destructure, |
154 | or break apart, a tuple as part of the `for` loop: | |
155 | ||
156 | <!-- Liz: We've been using the word "destructure" throughout the book in | |
157 | chapters 3, 4, 5, and 16. In chapter 3, in the "Grouping Values into Tuples" | |
158 | section, we said "This is called *destructuring*, because it breaks the single | |
159 | tuple into three parts.". So I don't think we need to define destructure again | |
160 | in this chapter, but I've added a small parenthetical here in case the reader | |
161 | forgets. /Carol --> | |
cc61c64b XL |
162 | |
163 | ```rust | |
164 | let v = vec![1, 2, 3]; | |
165 | ||
166 | for (index, value) in v.iter().enumerate() { | |
167 | println!("{} is at index {}", value, index); | |
168 | } | |
169 | ``` | |
170 | ||
171 | <span class="caption">Listing 18-3: Using a pattern in a `for` loop to | |
abe05a73 | 172 | destructure a tuple</span> |
cc61c64b XL |
173 | |
174 | This will print: | |
175 | ||
176 | ```text | |
177 | 1 is at index 0 | |
178 | 2 is at index 1 | |
179 | 3 is at index 2 | |
180 | ``` | |
181 | ||
abe05a73 XL |
182 | We use the `enumerate` method to adapt an iterator to produce a value and that |
183 | value’s index in the iterator, placed into a tuple. The first call to | |
184 | `enumerate` produces the tuple `(0, 1)`. When this value is matched to the | |
185 | pattern `(index, value)`, `index` will be 0 and `value` will be 1, printing our | |
186 | first line of output. | |
cc61c64b XL |
187 | |
188 | ### `let` Statements | |
189 | ||
abe05a73 XL |
190 | Before this chapter, we’d only explicitly discussed using patterns with `match` |
191 | and `if let`, but in fact we’ve used patterns in other places too, including | |
192 | `let` statements. For example, consider this straightforward variable | |
193 | assignment with `let`: | |
cc61c64b XL |
194 | |
195 | ```rust | |
196 | let x = 5; | |
197 | ``` | |
198 | ||
abe05a73 XL |
199 | We’ve done this hundreds of times throughout this book, and though you may not |
200 | have realized it, you were using patterns! A `let` statement looks like this, | |
cc61c64b XL |
201 | more formally: |
202 | ||
203 | ```text | |
204 | let PATTERN = EXPRESSION; | |
205 | ``` | |
206 | ||
abe05a73 XL |
207 | In statements like `let x = 5;` with a variable name in the `PATTERN` slot, the |
208 | variable name is just a particularly humble form of pattern. We compare the | |
209 | expression against the pattern, and assign any names we find. So for our `let x | |
210 | = 5;` example, `x` is a pattern that says “bind what matches here to the | |
211 | variable `x`.” And since the name `x` is the whole pattern, this pattern | |
212 | effectively means “bind everything to the variable `x`, whatever the value is.” | |
cc61c64b XL |
213 | |
214 | To see the pattern matching aspect of `let` a bit more clearly, consider | |
abe05a73 | 215 | Listing 18-4 where we’re using a pattern with `let` to destructure a tuple: |
cc61c64b XL |
216 | |
217 | ```rust | |
218 | let (x, y, z) = (1, 2, 3); | |
219 | ``` | |
220 | ||
221 | <span class="caption">Listing 18-4: Using a pattern to destructure a tuple and | |
abe05a73 XL |
222 | create three variables at once</span> |
223 | ||
224 | Here, we match a tuple against a pattern. Rust compares the value `(1, 2, 3)` | |
225 | to the pattern `(x, y, z)` and sees that the value matches the pattern, so will | |
226 | bind `1` to `x`, `2` to `y`, and `3` to `z`. You can think of this tuple | |
227 | pattern as nesting three individual variable patterns inside of it. | |
228 | ||
229 | <!-- so if we have a pattern of four elements, say (w, x, y, z), but only three | |
230 | values, would the values would not bind at all? --> | |
231 | <!-- Either too many or too few elements in the pattern is a type error. I've | |
232 | added a small example below to illustrate. /Carol --> | |
cc61c64b | 233 | |
abe05a73 XL |
234 | If the number of elements in the pattern don’t match the number of elements in |
235 | the tuple, the overall type won’t match and we’ll get a compiler error. For | |
236 | example, Listing 18-5 shows an attempt to destructure into two variables a | |
237 | tuple with three elements that won’t work: | |
238 | ||
239 | ```rust,ignore | |
240 | let (x, y) = (1, 2, 3); | |
241 | ``` | |
242 | ||
243 | <span class="caption">Listing 18-5: Incorrectly constructing a pattern whose | |
244 | variables don’t match the number of elements in the tuple</span> | |
245 | ||
246 | Attempting to compile this code gives us this type error: | |
247 | ||
248 | ```text | |
249 | error[E0308]: mismatched types | |
250 | --> src/main.rs:2:9 | |
251 | | | |
252 | 2 | let (x, y) = (1, 2, 3); | |
253 | | ^^^^^^ expected a tuple with 3 elements, found one with 2 elements | |
254 | | | |
255 | = note: expected type `({integer}, {integer}, {integer})` | |
256 | found type `(_, _)` | |
257 | ``` | |
cc61c64b | 258 | |
abe05a73 XL |
259 | If we wanted to ignore one or more of the values in the tuple, we could use `_` |
260 | or `..` as we’ll see in the “Ignoring Values in a Pattern” section. If the | |
261 | problem was that we had too many variables in the pattern, the solution would | |
262 | be to make the types match by removing variables so that the number of | |
263 | variables is equal to the number of elements in the tuple. | |
cc61c64b XL |
264 | |
265 | ### Function Parameters | |
266 | ||
abe05a73 XL |
267 | Function parameters can also be patterns. The code in Listing 18-6, declaring a |
268 | function named `foo` that takes one parameter named `x` of type `i32`, should | |
269 | by now look familiar: | |
cc61c64b XL |
270 | |
271 | ```rust | |
272 | fn foo(x: i32) { | |
273 | // code goes here | |
274 | } | |
275 | ``` | |
276 | ||
abe05a73 | 277 | <span class="caption">Listing 18-6: A function signature uses patterns in the |
cc61c64b XL |
278 | parameters</span> |
279 | ||
abe05a73 XL |
280 | The `x` part is a pattern! Like we did with `let`, we could match a tuple in a |
281 | function’s arguments to the pattern. Listing 18-7 splits apart the values in a | |
282 | tuple as we pass it to a function: | |
cc61c64b XL |
283 | |
284 | <span class="filename">Filename: src/main.rs</span> | |
285 | ||
286 | ```rust | |
287 | fn print_coordinates(&(x, y): &(i32, i32)) { | |
288 | println!("Current location: ({}, {})", x, y); | |
289 | } | |
290 | ||
291 | fn main() { | |
292 | let point = (3, 5); | |
293 | print_coordinates(&point); | |
294 | } | |
295 | ``` | |
296 | ||
abe05a73 | 297 | <span class="caption">Listing 18-7: A function with parameters that destructure |
cc61c64b XL |
298 | a tuple</span> |
299 | ||
abe05a73 XL |
300 | This will print `Current location: (3, 5)`. The values `&(3, 5)` match the |
301 | pattern `&(x, y)`, so `x` gets the value 3, and `y` gets the value 5. | |
cc61c64b | 302 | |
abe05a73 XL |
303 | We can use patterns in closure parameter lists in the same way, too, because |
304 | closures are similar to functions, as we discussed in Chapter 13. | |
cc61c64b | 305 | |
abe05a73 XL |
306 | We’ve seen several ways of using patterns now, but patterns do not work the |
307 | same in every place we can use them; in some places, the patterns must be | |
308 | *irrefutable*, meaning they must match any value provided. In other | |
309 | circumstances, they may be refutable. Let’s discuss that next. |