]>
Commit | Line | Data |
---|---|---|
13cf67c4 XL |
1 | ## Pattern Syntax |
2 | ||
3 | Throughout the book, you’ve seen examples of many kinds of patterns. In this | |
4 | section, we gather all the syntax valid in patterns and discuss why you might | |
5 | want to use each one. | |
6 | ||
7 | ### Matching Literals | |
8 | ||
9 | As you saw in Chapter 6, you can match patterns against literals directly. The | |
10 | following code gives some examples: | |
11 | ||
12 | ```rust | |
13 | let x = 1; | |
14 | ||
15 | match x { | |
16 | 1 => println!("one"), | |
17 | 2 => println!("two"), | |
18 | 3 => println!("three"), | |
19 | _ => println!("anything"), | |
20 | } | |
21 | ``` | |
22 | ||
23 | This code prints `one` because the value in `x` is 1. This syntax is useful | |
24 | when you want your code to take an action if it gets a particular concrete | |
25 | value. | |
26 | ||
27 | ### Matching Named Variables | |
28 | ||
29 | Named variables are irrefutable patterns that match any value, and we’ve used | |
30 | them many times in the book. However, there is a complication when you use | |
31 | named variables in `match` expressions. Because `match` starts a new scope, | |
32 | variables declared as part of a pattern inside the `match` expression will | |
33 | shadow those with the same name outside the `match` construct, as is the case | |
34 | with all variables. In Listing 18-11, we declare a variable named `x` with the | |
35 | value `Some(5)` and a variable `y` with the value `10`. We then create a | |
36 | `match` expression on the value `x`. Look at the patterns in the match arms and | |
37 | `println!` at the end, and try to figure out what the code will print before | |
38 | running this code or reading further. | |
39 | ||
40 | <span class="filename">Filename: src/main.rs</span> | |
41 | ||
42 | ```rust | |
43 | fn main() { | |
44 | let x = Some(5); | |
45 | let y = 10; | |
46 | ||
47 | match x { | |
48 | Some(50) => println!("Got 50"), | |
49 | Some(y) => println!("Matched, y = {:?}", y), | |
50 | _ => println!("Default case, x = {:?}", x), | |
51 | } | |
52 | ||
53 | println!("at the end: x = {:?}, y = {:?}", x, y); | |
54 | } | |
55 | ``` | |
56 | ||
57 | <span class="caption">Listing 18-11: A `match` expression with an arm that | |
58 | introduces a shadowed variable `y`</span> | |
59 | ||
60 | Let’s walk through what happens when the `match` expression runs. The pattern | |
61 | in the first match arm doesn’t match the defined value of `x`, so the code | |
62 | continues. | |
63 | ||
64 | The pattern in the second match arm introduces a new variable named `y` that | |
65 | will match any value inside a `Some` value. Because we’re in a new scope inside | |
66 | the `match` expression, this is a new `y` variable, not the `y` we declared at | |
67 | the beginning with the value 10. This new `y` binding will match any value | |
68 | inside a `Some`, which is what we have in `x`. Therefore, this new `y` binds to | |
69 | the inner value of the `Some` in `x`. That value is `5`, so the expression for | |
70 | that arm executes and prints `Matched, y = 5`. | |
71 | ||
72 | If `x` had been a `None` value instead of `Some(5)`, the patterns in the first | |
73 | two arms wouldn’t have matched, so the value would have matched to the | |
74 | underscore. We didn’t introduce the `x` variable in the pattern of the | |
75 | underscore arm, so the `x` in the expression is still the outer `x` that hasn’t | |
76 | been shadowed. In this hypothetical case, the `match` would print `Default | |
77 | case, x = None`. | |
78 | ||
79 | When the `match` expression is done, its scope ends, and so does the scope of | |
80 | the inner `y`. The last `println!` produces `at the end: x = Some(5), y = 10`. | |
81 | ||
82 | To create a `match` expression that compares the values of the outer `x` and | |
83 | `y`, rather than introducing a shadowed variable, we would need to use a match | |
9fa01778 XL |
84 | guard conditional instead. We’ll talk about match guards later in the [“Extra |
85 | Conditionals with Match Guards”](#extra-conditionals-with-match-guards)<!-- | |
86 | ignore --> section. | |
13cf67c4 XL |
87 | |
88 | ### Multiple Patterns | |
89 | ||
90 | In `match` expressions, you can match multiple patterns using the `|` syntax, | |
91 | which means *or*. For example, the following code matches the value of `x` | |
92 | against the match arms, the first of which has an *or* option, meaning if the | |
93 | value of `x` matches either of the values in that arm, that arm’s code will | |
94 | run: | |
95 | ||
96 | ```rust | |
97 | let x = 1; | |
98 | ||
99 | match x { | |
100 | 1 | 2 => println!("one or two"), | |
101 | 3 => println!("three"), | |
102 | _ => println!("anything"), | |
103 | } | |
104 | ``` | |
105 | ||
106 | This code prints `one or two`. | |
107 | ||
108 | ### Matching Ranges of Values with `...` | |
109 | ||
110 | The `...` syntax allows us to match to an inclusive range of values. In the | |
111 | following code, when a pattern matches any of the values within the range, that | |
112 | arm will execute: | |
113 | ||
114 | ```rust | |
115 | let x = 5; | |
116 | ||
117 | match x { | |
48663c56 | 118 | 1...5 => println!("one through five"), |
13cf67c4 XL |
119 | _ => println!("something else"), |
120 | } | |
121 | ``` | |
122 | ||
123 | If `x` is 1, 2, 3, 4, or 5, the first arm will match. This syntax is more | |
48663c56 XL |
124 | convenient than using the `|` operator to express the same idea; instead of |
125 | `1...5`, we would have to specify `1 | 2 | 3 | 4 | 5` if we used `|`. | |
126 | Specifying a range is much shorter, especially if we want to match, say, any | |
127 | number between 1 and 1,000! | |
13cf67c4 XL |
128 | |
129 | Ranges are only allowed with numeric values or `char` values, because the | |
130 | compiler checks that the range isn’t empty at compile time. The only types for | |
131 | which Rust can tell if a range is empty or not are `char` and numeric values. | |
132 | ||
133 | Here is an example using ranges of `char` values: | |
134 | ||
135 | ```rust | |
136 | let x = 'c'; | |
137 | ||
138 | match x { | |
48663c56 XL |
139 | 'a'...'j' => println!("early ASCII letter"), |
140 | 'k'...'z' => println!("late ASCII letter"), | |
13cf67c4 XL |
141 | _ => println!("something else"), |
142 | } | |
143 | ``` | |
144 | ||
145 | Rust can tell that `c` is within the first pattern’s range and prints `early | |
146 | ASCII letter`. | |
147 | ||
148 | ### Destructuring to Break Apart Values | |
149 | ||
150 | We can also use patterns to destructure structs, enums, tuples, and references | |
151 | to use different parts of these values. Let’s walk through each value. | |
152 | ||
153 | #### Destructuring Structs | |
154 | ||
155 | Listing 18-12 shows a `Point` struct with two fields, `x` and `y`, that we can | |
156 | break apart using a pattern with a `let` statement. | |
157 | ||
158 | <span class="filename">Filename: src/main.rs</span> | |
159 | ||
160 | ```rust | |
161 | struct Point { | |
162 | x: i32, | |
163 | y: i32, | |
164 | } | |
165 | ||
166 | fn main() { | |
167 | let p = Point { x: 0, y: 7 }; | |
168 | ||
169 | let Point { x: a, y: b } = p; | |
170 | assert_eq!(0, a); | |
171 | assert_eq!(7, b); | |
172 | } | |
173 | ``` | |
174 | ||
175 | <span class="caption">Listing 18-12: Destructuring a struct’s fields into | |
176 | separate variables</span> | |
177 | ||
178 | This code creates the variables `a` and `b` that match the values of the `x` | |
69743fb6 | 179 | and `y` fields of the `p` struct. This example shows that the names of the |
13cf67c4 XL |
180 | variables in the pattern don’t have to match the field names of the struct. But |
181 | it’s common to want the variable names to match the field names to make it | |
182 | easier to remember which variables came from which fields. | |
183 | ||
184 | Because having variable names match the fields is common and because writing | |
185 | `let Point { x: x, y: y } = p;` contains a lot of duplication, there is a | |
186 | shorthand for patterns that match struct fields: you only need to list the name | |
187 | of the struct field, and the variables created from the pattern will have the | |
188 | same names. Listing 18-13 shows code that behaves in the same way as the code | |
189 | in Listing 18-12, but the variables created in the `let` pattern are `x` and | |
190 | `y` instead of `a` and `b`. | |
191 | ||
192 | <span class="filename">Filename: src/main.rs</span> | |
193 | ||
194 | ```rust | |
195 | struct Point { | |
196 | x: i32, | |
197 | y: i32, | |
198 | } | |
199 | ||
200 | fn main() { | |
201 | let p = Point { x: 0, y: 7 }; | |
202 | ||
203 | let Point { x, y } = p; | |
204 | assert_eq!(0, x); | |
205 | assert_eq!(7, y); | |
206 | } | |
207 | ``` | |
208 | ||
209 | <span class="caption">Listing 18-13: Destructuring struct fields using struct | |
210 | field shorthand</span> | |
211 | ||
212 | This code creates the variables `x` and `y` that match the `x` and `y` fields | |
213 | of the `p` variable. The outcome is that the variables `x` and `y` contain the | |
214 | values from the `p` struct. | |
215 | ||
216 | We can also destructure with literal values as part of the struct pattern | |
217 | rather than creating variables for all the fields. Doing so allows us to test | |
218 | some of the fields for particular values while creating variables to | |
219 | destructure the other fields. | |
220 | ||
221 | Listing 18-14 shows a `match` expression that separates `Point` values into | |
222 | three cases: points that lie directly on the `x` axis (which is true when `y = | |
223 | 0`), on the `y` axis (`x = 0`), or neither. | |
224 | ||
225 | <span class="filename">Filename: src/main.rs</span> | |
226 | ||
227 | ```rust | |
228 | # struct Point { | |
229 | # x: i32, | |
230 | # y: i32, | |
231 | # } | |
232 | # | |
233 | fn main() { | |
234 | let p = Point { x: 0, y: 7 }; | |
235 | ||
236 | match p { | |
237 | Point { x, y: 0 } => println!("On the x axis at {}", x), | |
238 | Point { x: 0, y } => println!("On the y axis at {}", y), | |
239 | Point { x, y } => println!("On neither axis: ({}, {})", x, y), | |
240 | } | |
241 | } | |
242 | ``` | |
243 | ||
244 | <span class="caption">Listing 18-14: Destructuring and matching literal values | |
245 | in one pattern</span> | |
246 | ||
247 | The first arm will match any point that lies on the `x` axis by specifying that | |
248 | the `y` field matches if its value matches the literal `0`. The pattern still | |
249 | creates an `x` variable that we can use in the code for this arm. | |
250 | ||
251 | Similarly, the second arm matches any point on the `y` axis by specifying that | |
252 | the `x` field matches if its value is `0` and creates a variable `y` for the | |
253 | value of the `y` field. The third arm doesn’t specify any literals, so it | |
254 | matches any other `Point` and creates variables for both the `x` and `y` fields. | |
255 | ||
256 | In this example, the value `p` matches the second arm by virtue of `x` | |
257 | containing a 0, so this code will print `On the y axis at 7`. | |
258 | ||
259 | #### Destructuring Enums | |
260 | ||
261 | We’ve destructured enums earlier in this book, for example, when we | |
262 | destructured `Option<i32>` in Listing 6-5 in Chapter 6. One detail we haven’t | |
263 | mentioned explicitly is that the pattern to destructure an enum should | |
264 | correspond to the way the data stored within the enum is defined. As an | |
265 | example, in Listing 18-15 we use the `Message` enum from Listing 6-2 and write | |
266 | a `match` with patterns that will destructure each inner value. | |
267 | ||
268 | <span class="filename">Filename: src/main.rs</span> | |
269 | ||
270 | ```rust | |
271 | enum Message { | |
272 | Quit, | |
273 | Move { x: i32, y: i32 }, | |
274 | Write(String), | |
275 | ChangeColor(i32, i32, i32), | |
276 | } | |
277 | ||
278 | fn main() { | |
279 | let msg = Message::ChangeColor(0, 160, 255); | |
280 | ||
281 | match msg { | |
282 | Message::Quit => { | |
283 | println!("The Quit variant has no data to destructure.") | |
284 | }, | |
285 | Message::Move { x, y } => { | |
286 | println!( | |
287 | "Move in the x direction {} and in the y direction {}", | |
288 | x, | |
289 | y | |
290 | ); | |
291 | } | |
292 | Message::Write(text) => println!("Text message: {}", text), | |
293 | Message::ChangeColor(r, g, b) => { | |
294 | println!( | |
295 | "Change the color to red {}, green {}, and blue {}", | |
296 | r, | |
297 | g, | |
298 | b | |
299 | ) | |
300 | } | |
301 | } | |
302 | } | |
303 | ``` | |
304 | ||
305 | <span class="caption">Listing 18-15: Destructuring enum variants that hold | |
306 | different kinds of values</span> | |
307 | ||
308 | This code will print `Change the color to red 0, green 160, and blue 255`. Try | |
309 | changing the value of `msg` to see the code from the other arms run. | |
310 | ||
311 | For enum variants without any data, like `Message::Quit`, we can’t destructure | |
312 | the value any further. We can only match on the literal `Message::Quit` value, | |
313 | and no variables are in that pattern. | |
314 | ||
315 | For struct-like enum variants, such as `Message::Move`, we can use a pattern | |
316 | similar to the pattern we specify to match structs. After the variant name, we | |
317 | place curly brackets and then list the fields with variables so we break apart | |
318 | the pieces to use in the code for this arm. Here we use the shorthand form as | |
319 | we did in Listing 18-13. | |
320 | ||
321 | For tuple-like enum variants, like `Message::Write` that holds a tuple with one | |
322 | element and `Message::ChangeColor` that holds a tuple with three elements, the | |
323 | pattern is similar to the pattern we specify to match tuples. The number of | |
324 | variables in the pattern must match the number of elements in the variant we’re | |
325 | matching. | |
326 | ||
9fa01778 | 327 | #### Destructuring Nested Structs and Enums |
13cf67c4 | 328 | |
532ac7d7 XL |
329 | Until now, all our examples have been matching structs or enums that were one |
330 | level deep. Matching can work on nested items too! | |
13cf67c4 | 331 | |
532ac7d7 XL |
332 | For example, we can refactor the code in Listing 18-15 to support RGB and HSV |
333 | colors in the `ChangeColor` message, as shown in Listing 18-16. | |
13cf67c4 XL |
334 | |
335 | ```rust | |
336 | enum Color { | |
337 | Rgb(i32, i32, i32), | |
48663c56 | 338 | Hsv(i32, i32, i32), |
13cf67c4 XL |
339 | } |
340 | ||
341 | enum Message { | |
342 | Quit, | |
343 | Move { x: i32, y: i32 }, | |
344 | Write(String), | |
345 | ChangeColor(Color), | |
346 | } | |
347 | ||
348 | fn main() { | |
349 | let msg = Message::ChangeColor(Color::Hsv(0, 160, 255)); | |
350 | ||
351 | match msg { | |
352 | Message::ChangeColor(Color::Rgb(r, g, b)) => { | |
353 | println!( | |
354 | "Change the color to red {}, green {}, and blue {}", | |
355 | r, | |
356 | g, | |
357 | b | |
9fa01778 | 358 | ) |
13cf67c4 XL |
359 | }, |
360 | Message::ChangeColor(Color::Hsv(h, s, v)) => { | |
361 | println!( | |
362 | "Change the color to hue {}, saturation {}, and value {}", | |
363 | h, | |
364 | s, | |
365 | v | |
366 | ) | |
367 | } | |
368 | _ => () | |
369 | } | |
370 | } | |
371 | ``` | |
372 | ||
9fa01778 | 373 | <span class="caption">Listing 18-16: Matching on nested enums</span> |
13cf67c4 | 374 | |
9fa01778 | 375 | The pattern of the first arm in the `match` expression matches a |
532ac7d7 XL |
376 | `Message::ChangeColor` enum variant that contains a `Color::Rgb` variant; then |
377 | the pattern binds to the three inner `i32` values. The pattern of the second | |
378 | arm also matches a `Message::ChangeColor` enum variant, but the inner enum | |
379 | matches the `Color::Hsv` variant instead. We can specify these complex | |
380 | conditions in one `match` expression, even though two enums are involved. | |
13cf67c4 XL |
381 | |
382 | #### Destructuring Structs and Tuples | |
383 | ||
384 | We can mix, match, and nest destructuring patterns in even more complex ways. | |
385 | The following example shows a complicated destructure where we nest structs and | |
386 | tuples inside a tuple and destructure all the primitive values out: | |
387 | ||
388 | ```rust | |
389 | # struct Point { | |
390 | # x: i32, | |
391 | # y: i32, | |
392 | # } | |
393 | # | |
394 | let ((feet, inches), Point {x, y}) = ((3, 10), Point { x: 3, y: -10 }); | |
395 | ``` | |
396 | ||
397 | This code lets us break complex types into their component parts so we can use | |
398 | the values we’re interested in separately. | |
399 | ||
400 | Destructuring with patterns is a convenient way to use pieces of values, such | |
401 | as the value from each field in a struct, separately from each other. | |
402 | ||
403 | ### Ignoring Values in a Pattern | |
404 | ||
405 | You’ve seen that it’s sometimes useful to ignore values in a pattern, such as | |
406 | in the last arm of a `match`, to get a catchall that doesn’t actually do | |
407 | anything but does account for all remaining possible values. There are a few | |
408 | ways to ignore entire values or parts of values in a pattern: using the `_` | |
409 | pattern (which you’ve seen), using the `_` pattern within another pattern, | |
410 | using a name that starts with an underscore, or using `..` to ignore remaining | |
411 | parts of a value. Let’s explore how and why to use each of these patterns. | |
412 | ||
413 | #### Ignoring an Entire Value with `_` | |
414 | ||
415 | We’ve used the underscore (`_`) as a wildcard pattern that will match any value | |
416 | but not bind to the value. Although the underscore `_` pattern is especially | |
417 | useful as the last arm in a `match` expression, we can use it in any pattern, | |
418 | including function parameters, as shown in Listing 18-17. | |
419 | ||
420 | <span class="filename">Filename: src/main.rs</span> | |
421 | ||
422 | ```rust | |
423 | fn foo(_: i32, y: i32) { | |
424 | println!("This code only uses the y parameter: {}", y); | |
425 | } | |
426 | ||
427 | fn main() { | |
428 | foo(3, 4); | |
429 | } | |
430 | ``` | |
431 | ||
432 | <span class="caption">Listing 18-17: Using `_` in a function signature</span> | |
433 | ||
434 | This code will completely ignore the value passed as the first argument, `3`, | |
435 | and will print `This code only uses the y parameter: 4`. | |
436 | ||
437 | In most cases when you no longer need a particular function parameter, you | |
438 | would change the signature so it doesn’t include the unused parameter. Ignoring | |
439 | a function parameter can be especially useful in some cases, for example, when | |
440 | implementing a trait when you need a certain type signature but the function | |
441 | body in your implementation doesn’t need one of the parameters. The compiler | |
442 | will then not warn about unused function parameters, as it would if you used a | |
443 | name instead. | |
444 | ||
445 | #### Ignoring Parts of a Value with a Nested `_` | |
446 | ||
447 | We can also use `_` inside another pattern to ignore just part of a value, for | |
448 | example, when we want to test for only part of a value but have no use for the | |
449 | other parts in the corresponding code we want to run. Listing 18-18 shows code | |
450 | responsible for managing a setting’s value. The business requirements are that | |
451 | the user should not be allowed to overwrite an existing customization of a | |
532ac7d7 | 452 | setting but can unset the setting and give it a value if it is currently unset. |
13cf67c4 XL |
453 | |
454 | ```rust | |
455 | let mut setting_value = Some(5); | |
456 | let new_setting_value = Some(10); | |
457 | ||
458 | match (setting_value, new_setting_value) { | |
459 | (Some(_), Some(_)) => { | |
460 | println!("Can't overwrite an existing customized value"); | |
461 | } | |
462 | _ => { | |
463 | setting_value = new_setting_value; | |
464 | } | |
465 | } | |
466 | ||
467 | println!("setting is {:?}", setting_value); | |
468 | ``` | |
469 | ||
470 | <span class="caption">Listing 18-18: Using an underscore within patterns that | |
471 | match `Some` variants when we don’t need to use the value inside the | |
472 | `Some`</span> | |
473 | ||
474 | This code will print `Can't overwrite an existing customized value` and then | |
475 | `setting is Some(5)`. In the first match arm, we don’t need to match on or use | |
476 | the values inside either `Some` variant, but we do need to test for the case | |
477 | when `setting_value` and `new_setting_value` are the `Some` variant. In that | |
478 | case, we print why we’re not changing `setting_value`, and it doesn’t get | |
479 | changed. | |
480 | ||
481 | In all other cases (if either `setting_value` or `new_setting_value` are | |
482 | `None`) expressed by the `_` pattern in the second arm, we want to allow | |
483 | `new_setting_value` to become `setting_value`. | |
484 | ||
485 | We can also use underscores in multiple places within one pattern to ignore | |
486 | particular values. Listing 18-19 shows an example of ignoring the second and | |
487 | fourth values in a tuple of five items. | |
488 | ||
489 | ```rust | |
490 | let numbers = (2, 4, 8, 16, 32); | |
491 | ||
492 | match numbers { | |
493 | (first, _, third, _, fifth) => { | |
494 | println!("Some numbers: {}, {}, {}", first, third, fifth) | |
495 | }, | |
496 | } | |
497 | ``` | |
498 | ||
499 | <span class="caption">Listing 18-19: Ignoring multiple parts of a tuple</span> | |
500 | ||
501 | This code will print `Some numbers: 2, 8, 32`, and the values 4 and 16 will be | |
502 | ignored. | |
503 | ||
504 | #### Ignoring an Unused Variable by Starting Its Name with `_` | |
505 | ||
506 | If you create a variable but don’t use it anywhere, Rust will usually issue a | |
507 | warning because that could be a bug. But sometimes it’s useful to create a | |
508 | variable you won’t use yet, such as when you’re prototyping or just starting a | |
509 | project. In this situation, you can tell Rust not to warn you about the unused | |
510 | variable by starting the name of the variable with an underscore. In Listing | |
511 | 18-20, we create two unused variables, but when we run this code, we should | |
512 | only get a warning about one of them. | |
513 | ||
514 | <span class="filename">Filename: src/main.rs</span> | |
515 | ||
516 | ```rust | |
517 | fn main() { | |
518 | let _x = 5; | |
519 | let y = 10; | |
520 | } | |
521 | ``` | |
522 | ||
523 | <span class="caption">Listing 18-20: Starting a variable name with an | |
524 | underscore to avoid getting unused variable warnings</span> | |
525 | ||
526 | Here we get a warning about not using the variable `y`, but we don’t get a | |
527 | warning about not using the variable preceded by the underscore. | |
528 | ||
529 | Note that there is a subtle difference between using only `_` and using a name | |
530 | that starts with an underscore. The syntax `_x` still binds the value to the | |
531 | variable, whereas `_` doesn’t bind at all. To show a case where this | |
532 | distinction matters, Listing 18-21 will provide us with an error. | |
533 | ||
534 | ```rust,ignore,does_not_compile | |
535 | let s = Some(String::from("Hello!")); | |
536 | ||
537 | if let Some(_s) = s { | |
538 | println!("found a string"); | |
539 | } | |
540 | ||
541 | println!("{:?}", s); | |
542 | ``` | |
543 | ||
544 | <span class="caption">Listing 18-21: An unused variable starting with an | |
545 | underscore still binds the value, which might take ownership of the value</span> | |
546 | ||
547 | We’ll receive an error because the `s` value will still be moved into `_s`, | |
548 | which prevents us from using `s` again. However, using the underscore by itself | |
549 | doesn’t ever bind to the value. Listing 18-22 will compile without any errors | |
550 | because `s` doesn’t get moved into `_`. | |
551 | ||
552 | ```rust | |
553 | let s = Some(String::from("Hello!")); | |
554 | ||
555 | if let Some(_) = s { | |
556 | println!("found a string"); | |
557 | } | |
558 | ||
559 | println!("{:?}", s); | |
560 | ``` | |
561 | ||
562 | <span class="caption">Listing 18-22: Using an underscore does not bind the | |
563 | value</span> | |
564 | ||
565 | This code works just fine because we never bind `s` to anything; it isn’t moved. | |
566 | ||
567 | #### Ignoring Remaining Parts of a Value with `..` | |
568 | ||
569 | With values that have many parts, we can use the `..` syntax to use only a few | |
570 | parts and ignore the rest, avoiding the need to list underscores for each | |
571 | ignored value. The `..` pattern ignores any parts of a value that we haven’t | |
572 | explicitly matched in the rest of the pattern. In Listing 18-23, we have a | |
573 | `Point` struct that holds a coordinate in three-dimensional space. In the | |
574 | `match` expression, we want to operate only on the `x` coordinate and ignore | |
575 | the values in the `y` and `z` fields. | |
576 | ||
577 | ```rust | |
578 | struct Point { | |
579 | x: i32, | |
580 | y: i32, | |
581 | z: i32, | |
582 | } | |
583 | ||
584 | let origin = Point { x: 0, y: 0, z: 0 }; | |
585 | ||
586 | match origin { | |
587 | Point { x, .. } => println!("x is {}", x), | |
588 | } | |
589 | ``` | |
590 | ||
591 | <span class="caption">Listing 18-23: Ignoring all fields of a `Point` except | |
592 | for `x` by using `..`</span> | |
593 | ||
594 | We list the `x` value and then just include the `..` pattern. This is quicker | |
595 | than having to list `y: _` and `z: _`, particularly when we’re working with | |
596 | structs that have lots of fields in situations where only one or two fields are | |
597 | relevant. | |
598 | ||
599 | The syntax `..` will expand to as many values as it needs to be. Listing 18-24 | |
600 | shows how to use `..` with a tuple. | |
601 | ||
602 | <span class="filename">Filename: src/main.rs</span> | |
603 | ||
604 | ```rust | |
605 | fn main() { | |
606 | let numbers = (2, 4, 8, 16, 32); | |
607 | ||
608 | match numbers { | |
609 | (first, .., last) => { | |
610 | println!("Some numbers: {}, {}", first, last); | |
611 | }, | |
612 | } | |
613 | } | |
614 | ``` | |
615 | ||
616 | <span class="caption">Listing 18-24: Matching only the first and last values in | |
617 | a tuple and ignoring all other values</span> | |
618 | ||
619 | In this code, the first and last value are matched with `first` and `last`. The | |
620 | `..` will match and ignore everything in the middle. | |
621 | ||
622 | However, using `..` must be unambiguous. If it is unclear which values are | |
623 | intended for matching and which should be ignored, Rust will give us an error. | |
624 | Listing 18-25 shows an example of using `..` ambiguously, so it will not | |
625 | compile. | |
626 | ||
627 | <span class="filename">Filename: src/main.rs</span> | |
628 | ||
629 | ```rust,ignore,does_not_compile | |
630 | fn main() { | |
631 | let numbers = (2, 4, 8, 16, 32); | |
632 | ||
633 | match numbers { | |
634 | (.., second, ..) => { | |
635 | println!("Some numbers: {}", second) | |
636 | }, | |
637 | } | |
638 | } | |
639 | ``` | |
640 | ||
641 | <span class="caption">Listing 18-25: An attempt to use `..` in an ambiguous | |
642 | way</span> | |
643 | ||
644 | When we compile this example, we get this error: | |
645 | ||
646 | ```text | |
647 | error: `..` can only be used once per tuple or tuple struct pattern | |
648 | --> src/main.rs:5:22 | |
649 | | | |
650 | 5 | (.., second, ..) => { | |
651 | | ^^ | |
652 | ``` | |
653 | ||
654 | It’s impossible for Rust to determine how many values in the tuple to ignore | |
655 | before matching a value with `second` and then how many further values to | |
656 | ignore thereafter. This code could mean that we want to ignore `2`, bind | |
657 | `second` to `4`, and then ignore `8`, `16`, and `32`; or that we want to ignore | |
658 | `2` and `4`, bind `second` to `8`, and then ignore `16` and `32`; and so forth. | |
659 | The variable name `second` doesn’t mean anything special to Rust, so we get a | |
660 | compiler error because using `..` in two places like this is ambiguous. | |
661 | ||
662 | ### Extra Conditionals with Match Guards | |
663 | ||
664 | A *match guard* is an additional `if` condition specified after the pattern in | |
665 | a `match` arm that must also match, along with the pattern matching, for that | |
666 | arm to be chosen. Match guards are useful for expressing more complex ideas | |
667 | than a pattern alone allows. | |
668 | ||
669 | The condition can use variables created in the pattern. Listing 18-26 shows a | |
670 | `match` where the first arm has the pattern `Some(x)` and also has a match | |
671 | guard of `if x < 5`. | |
672 | ||
673 | ```rust | |
674 | let num = Some(4); | |
675 | ||
676 | match num { | |
677 | Some(x) if x < 5 => println!("less than five: {}", x), | |
678 | Some(x) => println!("{}", x), | |
679 | None => (), | |
680 | } | |
681 | ``` | |
682 | ||
683 | <span class="caption">Listing 18-26: Adding a match guard to a pattern</span> | |
684 | ||
685 | This example will print `less than five: 4`. When `num` is compared to the | |
686 | pattern in the first arm, it matches, because `Some(4)` matches `Some(x)`. Then | |
687 | the match guard checks whether the value in `x` is less than `5`, and because | |
688 | it is, the first arm is selected. | |
689 | ||
690 | If `num` had been `Some(10)` instead, the match guard in the first arm would | |
691 | have been false because 10 is not less than 5. Rust would then go to the second | |
692 | arm, which would match because the second arm doesn’t have a match guard and | |
693 | therefore matches any `Some` variant. | |
694 | ||
695 | There is no way to express the `if x < 5` condition within a pattern, so the | |
696 | match guard gives us the ability to express this logic. | |
697 | ||
698 | In Listing 18-11, we mentioned that we could use match guards to solve our | |
699 | pattern-shadowing problem. Recall that a new variable was created inside the | |
700 | pattern in the `match` expression instead of using the variable outside the | |
701 | `match`. That new variable meant we couldn’t test against the value of the | |
9fa01778 | 702 | outer variable. Listing 18-27 shows how we can use a match guard to fix this |
13cf67c4 XL |
703 | problem. |
704 | ||
705 | <span class="filename">Filename: src/main.rs</span> | |
706 | ||
707 | ```rust | |
708 | fn main() { | |
709 | let x = Some(5); | |
710 | let y = 10; | |
711 | ||
712 | match x { | |
713 | Some(50) => println!("Got 50"), | |
714 | Some(n) if n == y => println!("Matched, n = {:?}", n), | |
715 | _ => println!("Default case, x = {:?}", x), | |
716 | } | |
717 | ||
718 | println!("at the end: x = {:?}, y = {:?}", x, y); | |
719 | } | |
720 | ``` | |
721 | ||
722 | <span class="caption">Listing 18-27: Using a match guard to test for equality | |
723 | with an outer variable</span> | |
724 | ||
725 | This code will now print `Default case, x = Some(5)`. The pattern in the second | |
726 | match arm doesn’t introduce a new variable `y` that would shadow the outer `y`, | |
727 | meaning we can use the outer `y` in the match guard. Instead of specifying the | |
728 | pattern as `Some(y)`, which would have shadowed the outer `y`, we specify | |
729 | `Some(n)`. This creates a new variable `n` that doesn’t shadow anything because | |
730 | there is no `n` variable outside the `match`. | |
731 | ||
732 | The match guard `if n == y` is not a pattern and therefore doesn’t introduce | |
733 | new variables. This `y` *is* the outer `y` rather than a new shadowed `y`, and | |
734 | we can look for a value that has the same value as the outer `y` by comparing | |
735 | `n` to `y`. | |
736 | ||
737 | You can also use the *or* operator `|` in a match guard to specify multiple | |
738 | patterns; the match guard condition will apply to all the patterns. Listing | |
9fa01778 | 739 | 18-28 shows the precedence of combining a match guard with a pattern that uses |
13cf67c4 XL |
740 | `|`. The important part of this example is that the `if y` match guard applies |
741 | to `4`, `5`, *and* `6`, even though it might look like `if y` only applies to | |
742 | `6`. | |
743 | ||
744 | ```rust | |
745 | let x = 4; | |
746 | let y = false; | |
747 | ||
748 | match x { | |
749 | 4 | 5 | 6 if y => println!("yes"), | |
750 | _ => println!("no"), | |
751 | } | |
752 | ``` | |
753 | ||
9fa01778 | 754 | <span class="caption">Listing 18-28: Combining multiple patterns with a match |
13cf67c4 XL |
755 | guard</span> |
756 | ||
757 | The match condition states that the arm only matches if the value of `x` is | |
758 | equal to `4`, `5`, or `6` *and* if `y` is `true`. When this code runs, the | |
759 | pattern of the first arm matches because `x` is `4`, but the match guard `if y` | |
760 | is false, so the first arm is not chosen. The code moves on to the second arm, | |
761 | which does match, and this program prints `no`. The reason is that the `if` | |
762 | condition applies to the whole pattern `4 | 5 | 6`, not only to the last value | |
763 | `6`. In other words, the precedence of a match guard in relation to a pattern | |
764 | behaves like this: | |
765 | ||
766 | ```text | |
767 | (4 | 5 | 6) if y => ... | |
768 | ``` | |
769 | ||
770 | rather than this: | |
771 | ||
772 | ```text | |
773 | 4 | 5 | (6 if y) => ... | |
774 | ``` | |
775 | ||
776 | After running the code, the precedence behavior is evident: if the match guard | |
777 | were applied only to the final value in the list of values specified using the | |
778 | `|` operator, the arm would have matched and the program would have printed | |
779 | `yes`. | |
780 | ||
781 | ### `@` Bindings | |
782 | ||
783 | The *at* operator (`@`) lets us create a variable that holds a value at the | |
784 | same time we’re testing that value to see whether it matches a pattern. Listing | |
9fa01778 | 785 | 18-29 shows an example where we want to test that a `Message::Hello` `id` field |
13cf67c4 XL |
786 | is within the range `3...7`. But we also want to bind the value to the variable |
787 | `id_variable` so we can use it in the code associated with the arm. We could | |
788 | name this variable `id`, the same as the field, but for this example we’ll use | |
789 | a different name. | |
790 | ||
791 | ```rust | |
792 | enum Message { | |
793 | Hello { id: i32 }, | |
794 | } | |
795 | ||
796 | let msg = Message::Hello { id: 5 }; | |
797 | ||
798 | match msg { | |
799 | Message::Hello { id: id_variable @ 3...7 } => { | |
800 | println!("Found an id in range: {}", id_variable) | |
801 | }, | |
802 | Message::Hello { id: 10...12 } => { | |
803 | println!("Found an id in another range") | |
804 | }, | |
805 | Message::Hello { id } => { | |
806 | println!("Found some other id: {}", id) | |
807 | }, | |
808 | } | |
809 | ``` | |
810 | ||
9fa01778 | 811 | <span class="caption">Listing 18-29: Using `@` to bind to a value in a pattern |
13cf67c4 XL |
812 | while also testing it</span> |
813 | ||
814 | This example will print `Found an id in range: 5`. By specifying `id_variable | |
815 | @` before the range `3...7`, we’re capturing whatever value matched the range | |
816 | while also testing that the value matched the range pattern. | |
817 | ||
818 | In the second arm, where we only have a range specified in the pattern, the code | |
819 | associated with the arm doesn’t have a variable that contains the actual value | |
820 | of the `id` field. The `id` field’s value could have been 10, 11, or 12, but | |
821 | the code that goes with that pattern doesn’t know which it is. The pattern code | |
822 | isn’t able to use the value from the `id` field, because we haven’t saved the | |
823 | `id` value in a variable. | |
824 | ||
825 | In the last arm, where we’ve specified a variable without a range, we do have | |
826 | the value available to use in the arm’s code in a variable named `id`. The | |
827 | reason is that we’ve used the struct field shorthand syntax. But we haven’t | |
828 | applied any test to the value in the `id` field in this arm, as we did with the | |
829 | first two arms: any value would match this pattern. | |
830 | ||
831 | Using `@` lets us test a value and save it in a variable within one pattern. | |
832 | ||
13cf67c4 XL |
833 | ## Summary |
834 | ||
835 | Rust’s patterns are very useful in that they help distinguish between different | |
836 | kinds of data. When used in `match` expressions, Rust ensures your patterns | |
837 | cover every possible value, or your program won’t compile. Patterns in `let` | |
838 | statements and function parameters make those constructs more useful, enabling | |
839 | the destructuring of values into smaller parts at the same time as assigning to | |
840 | variables. We can create simple or complex patterns to suit our needs. | |
841 | ||
842 | Next, for the penultimate chapter of the book, we’ll look at some advanced | |
843 | aspects of a variety of Rust’s features. |