]>
Commit | Line | Data |
---|---|---|
13cf67c4 XL |
1 | ## Pattern Syntax |
2 | ||
923072b8 FG |
3 | In this section, we gather all the syntax valid in patterns and discuss why and |
4 | when you might want to use each one. | |
13cf67c4 XL |
5 | |
6 | ### Matching Literals | |
7 | ||
8 | As you saw in Chapter 6, you can match patterns against literals directly. The | |
9 | following code gives some examples: | |
10 | ||
11 | ```rust | |
74b04a01 | 12 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/no-listing-01-literals/src/main.rs:here}} |
13cf67c4 XL |
13 | ``` |
14 | ||
15 | This code prints `one` because the value in `x` is 1. This syntax is useful | |
16 | when you want your code to take an action if it gets a particular concrete | |
17 | value. | |
18 | ||
19 | ### Matching Named Variables | |
20 | ||
21 | Named variables are irrefutable patterns that match any value, and we’ve used | |
22 | them many times in the book. However, there is a complication when you use | |
23 | named variables in `match` expressions. Because `match` starts a new scope, | |
24 | variables declared as part of a pattern inside the `match` expression will | |
25 | shadow those with the same name outside the `match` construct, as is the case | |
26 | with all variables. In Listing 18-11, we declare a variable named `x` with the | |
27 | value `Some(5)` and a variable `y` with the value `10`. We then create a | |
28 | `match` expression on the value `x`. Look at the patterns in the match arms and | |
29 | `println!` at the end, and try to figure out what the code will print before | |
30 | running this code or reading further. | |
31 | ||
32 | <span class="filename">Filename: src/main.rs</span> | |
33 | ||
34 | ```rust | |
74b04a01 | 35 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-11/src/main.rs:here}} |
13cf67c4 XL |
36 | ``` |
37 | ||
38 | <span class="caption">Listing 18-11: A `match` expression with an arm that | |
39 | introduces a shadowed variable `y`</span> | |
40 | ||
41 | Let’s walk through what happens when the `match` expression runs. The pattern | |
42 | in the first match arm doesn’t match the defined value of `x`, so the code | |
43 | continues. | |
44 | ||
45 | The pattern in the second match arm introduces a new variable named `y` that | |
46 | will match any value inside a `Some` value. Because we’re in a new scope inside | |
47 | the `match` expression, this is a new `y` variable, not the `y` we declared at | |
48 | the beginning with the value 10. This new `y` binding will match any value | |
49 | inside a `Some`, which is what we have in `x`. Therefore, this new `y` binds to | |
50 | the inner value of the `Some` in `x`. That value is `5`, so the expression for | |
51 | that arm executes and prints `Matched, y = 5`. | |
52 | ||
53 | If `x` had been a `None` value instead of `Some(5)`, the patterns in the first | |
54 | two arms wouldn’t have matched, so the value would have matched to the | |
55 | underscore. We didn’t introduce the `x` variable in the pattern of the | |
56 | underscore arm, so the `x` in the expression is still the outer `x` that hasn’t | |
57 | been shadowed. In this hypothetical case, the `match` would print `Default | |
58 | case, x = None`. | |
59 | ||
60 | When the `match` expression is done, its scope ends, and so does the scope of | |
61 | the inner `y`. The last `println!` produces `at the end: x = Some(5), y = 10`. | |
62 | ||
63 | To create a `match` expression that compares the values of the outer `x` and | |
64 | `y`, rather than introducing a shadowed variable, we would need to use a match | |
9fa01778 XL |
65 | guard conditional instead. We’ll talk about match guards later in the [“Extra |
66 | Conditionals with Match Guards”](#extra-conditionals-with-match-guards)<!-- | |
67 | ignore --> section. | |
13cf67c4 XL |
68 | |
69 | ### Multiple Patterns | |
70 | ||
71 | In `match` expressions, you can match multiple patterns using the `|` syntax, | |
923072b8 FG |
72 | which is the pattern *or* operator. For example, in the following code we match |
73 | the value of `x` against the match arms, the first of which has an *or* option, | |
74 | meaning if the value of `x` matches either of the values in that arm, that | |
75 | arm’s code will run: | |
13cf67c4 XL |
76 | |
77 | ```rust | |
74b04a01 | 78 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/no-listing-02-multiple-patterns/src/main.rs:here}} |
13cf67c4 XL |
79 | ``` |
80 | ||
81 | This code prints `one or two`. | |
82 | ||
e1599b0c | 83 | ### Matching Ranges of Values with `..=` |
13cf67c4 | 84 | |
e1599b0c | 85 | The `..=` syntax allows us to match to an inclusive range of values. In the |
923072b8 FG |
86 | following code, when a pattern matches any of the values within the given |
87 | range, that arm will execute: | |
13cf67c4 XL |
88 | |
89 | ```rust | |
74b04a01 | 90 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/no-listing-03-ranges/src/main.rs:here}} |
13cf67c4 XL |
91 | ``` |
92 | ||
93 | If `x` is 1, 2, 3, 4, or 5, the first arm will match. This syntax is more | |
923072b8 FG |
94 | convenient for multiple match values than using the `|` operator to express the |
95 | same idea; if we were to use `|` we would have to specify `1 | 2 | 3 | 4 | 5`. | |
48663c56 XL |
96 | Specifying a range is much shorter, especially if we want to match, say, any |
97 | number between 1 and 1,000! | |
13cf67c4 | 98 | |
923072b8 FG |
99 | The compiler checks that the range isn’t empty at compile time, and because the |
100 | only types for which Rust can tell if a range is empty or not are `char` and | |
101 | numeric values, ranges are only allowed with numeric or `char` values. | |
13cf67c4 XL |
102 | |
103 | Here is an example using ranges of `char` values: | |
104 | ||
105 | ```rust | |
74b04a01 | 106 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/no-listing-04-ranges-of-char/src/main.rs:here}} |
13cf67c4 XL |
107 | ``` |
108 | ||
5e7ed085 | 109 | Rust can tell that `'c'` is within the first pattern’s range and prints `early |
13cf67c4 XL |
110 | ASCII letter`. |
111 | ||
112 | ### Destructuring to Break Apart Values | |
113 | ||
5099ac24 FG |
114 | We can also use patterns to destructure structs, enums, and tuples to use |
115 | different parts of these values. Let’s walk through each value. | |
13cf67c4 XL |
116 | |
117 | #### Destructuring Structs | |
118 | ||
119 | Listing 18-12 shows a `Point` struct with two fields, `x` and `y`, that we can | |
120 | break apart using a pattern with a `let` statement. | |
121 | ||
122 | <span class="filename">Filename: src/main.rs</span> | |
123 | ||
124 | ```rust | |
74b04a01 | 125 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-12/src/main.rs}} |
13cf67c4 XL |
126 | ``` |
127 | ||
128 | <span class="caption">Listing 18-12: Destructuring a struct’s fields into | |
129 | separate variables</span> | |
130 | ||
131 | This code creates the variables `a` and `b` that match the values of the `x` | |
69743fb6 | 132 | and `y` fields of the `p` struct. This example shows that the names of the |
923072b8 FG |
133 | variables in the pattern don’t have to match the field names of the struct. |
134 | However, it’s common to match the variable names to the field names to make it | |
135 | easier to remember which variables came from which fields. Because of this | |
136 | common usage, and because writing `let Point { x: x, y: y } = p;` contains a | |
137 | lot of duplication, Rust has a shorthand for patterns that match struct fields: | |
138 | you only need to list the name of the struct field, and the variables created | |
139 | from the pattern will have the same names. Listing 18-13 behaves in the same | |
140 | way as the code in Listing 18-12, but the variables created in the `let` | |
141 | pattern are `x` and `y` instead of `a` and `b`. | |
13cf67c4 XL |
142 | |
143 | <span class="filename">Filename: src/main.rs</span> | |
144 | ||
145 | ```rust | |
74b04a01 | 146 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-13/src/main.rs}} |
13cf67c4 XL |
147 | ``` |
148 | ||
149 | <span class="caption">Listing 18-13: Destructuring struct fields using struct | |
150 | field shorthand</span> | |
151 | ||
152 | This code creates the variables `x` and `y` that match the `x` and `y` fields | |
153 | of the `p` variable. The outcome is that the variables `x` and `y` contain the | |
154 | values from the `p` struct. | |
155 | ||
156 | We can also destructure with literal values as part of the struct pattern | |
157 | rather than creating variables for all the fields. Doing so allows us to test | |
158 | some of the fields for particular values while creating variables to | |
159 | destructure the other fields. | |
160 | ||
923072b8 FG |
161 | In Listing 18-14, we have a `match` expression that separates `Point` values |
162 | into three cases: points that lie directly on the `x` axis (which is true when | |
163 | `y = 0`), on the `y` axis (`x = 0`), or neither. | |
13cf67c4 XL |
164 | |
165 | <span class="filename">Filename: src/main.rs</span> | |
166 | ||
167 | ```rust | |
74b04a01 | 168 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-14/src/main.rs:here}} |
13cf67c4 XL |
169 | ``` |
170 | ||
171 | <span class="caption">Listing 18-14: Destructuring and matching literal values | |
172 | in one pattern</span> | |
173 | ||
174 | The first arm will match any point that lies on the `x` axis by specifying that | |
175 | the `y` field matches if its value matches the literal `0`. The pattern still | |
176 | creates an `x` variable that we can use in the code for this arm. | |
177 | ||
178 | Similarly, the second arm matches any point on the `y` axis by specifying that | |
179 | the `x` field matches if its value is `0` and creates a variable `y` for the | |
180 | value of the `y` field. The third arm doesn’t specify any literals, so it | |
181 | matches any other `Point` and creates variables for both the `x` and `y` fields. | |
182 | ||
183 | In this example, the value `p` matches the second arm by virtue of `x` | |
184 | containing a 0, so this code will print `On the y axis at 7`. | |
185 | ||
923072b8 FG |
186 | Remember that a `match` expression stops checking arms once it has found the |
187 | first matching pattern, so even though `Point { x: 0, y: 0}` is on the `x` axis | |
188 | and the `y` axis, this code would only print `On the x axis at 0`. | |
189 | ||
13cf67c4 XL |
190 | #### Destructuring Enums |
191 | ||
923072b8 FG |
192 | We've destructured enums in this book (for example, Listing 6-5 in Chapter 6), |
193 | but haven’t yet explicitly discussed that the pattern to destructure an enum | |
194 | corresponds to the way the data stored within the enum is defined. As an | |
13cf67c4 XL |
195 | example, in Listing 18-15 we use the `Message` enum from Listing 6-2 and write |
196 | a `match` with patterns that will destructure each inner value. | |
197 | ||
198 | <span class="filename">Filename: src/main.rs</span> | |
199 | ||
200 | ```rust | |
74b04a01 | 201 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-15/src/main.rs}} |
13cf67c4 XL |
202 | ``` |
203 | ||
204 | <span class="caption">Listing 18-15: Destructuring enum variants that hold | |
205 | different kinds of values</span> | |
206 | ||
207 | This code will print `Change the color to red 0, green 160, and blue 255`. Try | |
208 | changing the value of `msg` to see the code from the other arms run. | |
209 | ||
210 | For enum variants without any data, like `Message::Quit`, we can’t destructure | |
211 | the value any further. We can only match on the literal `Message::Quit` value, | |
212 | and no variables are in that pattern. | |
213 | ||
214 | For struct-like enum variants, such as `Message::Move`, we can use a pattern | |
215 | similar to the pattern we specify to match structs. After the variant name, we | |
216 | place curly brackets and then list the fields with variables so we break apart | |
217 | the pieces to use in the code for this arm. Here we use the shorthand form as | |
218 | we did in Listing 18-13. | |
219 | ||
220 | For tuple-like enum variants, like `Message::Write` that holds a tuple with one | |
221 | element and `Message::ChangeColor` that holds a tuple with three elements, the | |
222 | pattern is similar to the pattern we specify to match tuples. The number of | |
223 | variables in the pattern must match the number of elements in the variant we’re | |
224 | matching. | |
225 | ||
9fa01778 | 226 | #### Destructuring Nested Structs and Enums |
13cf67c4 | 227 | |
923072b8 FG |
228 | So far, our examples have all been matching structs or enums one level deep, |
229 | but matching can work on nested items too! For example, we can refactor the | |
230 | code in Listing 18-15 to support RGB and HSV colors in the `ChangeColor` | |
231 | message, as shown in Listing 18-16. | |
13cf67c4 XL |
232 | |
233 | ```rust | |
74b04a01 | 234 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-16/src/main.rs}} |
13cf67c4 XL |
235 | ``` |
236 | ||
9fa01778 | 237 | <span class="caption">Listing 18-16: Matching on nested enums</span> |
13cf67c4 | 238 | |
9fa01778 | 239 | The pattern of the first arm in the `match` expression matches a |
532ac7d7 XL |
240 | `Message::ChangeColor` enum variant that contains a `Color::Rgb` variant; then |
241 | the pattern binds to the three inner `i32` values. The pattern of the second | |
242 | arm also matches a `Message::ChangeColor` enum variant, but the inner enum | |
923072b8 FG |
243 | matches `Color::Hsv` instead. We can specify these complex conditions in one |
244 | `match` expression, even though two enums are involved. | |
13cf67c4 XL |
245 | |
246 | #### Destructuring Structs and Tuples | |
247 | ||
248 | We can mix, match, and nest destructuring patterns in even more complex ways. | |
249 | The following example shows a complicated destructure where we nest structs and | |
250 | tuples inside a tuple and destructure all the primitive values out: | |
251 | ||
252 | ```rust | |
74b04a01 | 253 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/no-listing-05-destructuring-structs-and-tuples/src/main.rs:here}} |
13cf67c4 XL |
254 | ``` |
255 | ||
256 | This code lets us break complex types into their component parts so we can use | |
257 | the values we’re interested in separately. | |
258 | ||
259 | Destructuring with patterns is a convenient way to use pieces of values, such | |
260 | as the value from each field in a struct, separately from each other. | |
261 | ||
262 | ### Ignoring Values in a Pattern | |
263 | ||
264 | You’ve seen that it’s sometimes useful to ignore values in a pattern, such as | |
265 | in the last arm of a `match`, to get a catchall that doesn’t actually do | |
266 | anything but does account for all remaining possible values. There are a few | |
267 | ways to ignore entire values or parts of values in a pattern: using the `_` | |
268 | pattern (which you’ve seen), using the `_` pattern within another pattern, | |
269 | using a name that starts with an underscore, or using `..` to ignore remaining | |
270 | parts of a value. Let’s explore how and why to use each of these patterns. | |
271 | ||
272 | #### Ignoring an Entire Value with `_` | |
273 | ||
923072b8 FG |
274 | We’ve used the underscore as a wildcard pattern that will match any value but |
275 | not bind to the value. This is especially useful as the last arm in a `match` | |
276 | expression, but we can also use it in any pattern, including function | |
277 | parameters, as shown in Listing 18-17. | |
13cf67c4 XL |
278 | |
279 | <span class="filename">Filename: src/main.rs</span> | |
280 | ||
281 | ```rust | |
74b04a01 | 282 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-17/src/main.rs}} |
13cf67c4 XL |
283 | ``` |
284 | ||
285 | <span class="caption">Listing 18-17: Using `_` in a function signature</span> | |
286 | ||
923072b8 | 287 | This code will completely ignore the value `3` passed as the first argument, |
13cf67c4 XL |
288 | and will print `This code only uses the y parameter: 4`. |
289 | ||
290 | In most cases when you no longer need a particular function parameter, you | |
291 | would change the signature so it doesn’t include the unused parameter. Ignoring | |
923072b8 FG |
292 | a function parameter can be especially useful in cases when, for example, |
293 | you're implementing a trait when you need a certain type signature but the | |
294 | function body in your implementation doesn’t need one of the parameters. You | |
295 | then avoid getting a compiler warning about unused function parameters, as you | |
296 | would if you used a name instead. | |
13cf67c4 XL |
297 | |
298 | #### Ignoring Parts of a Value with a Nested `_` | |
299 | ||
300 | We can also use `_` inside another pattern to ignore just part of a value, for | |
301 | example, when we want to test for only part of a value but have no use for the | |
302 | other parts in the corresponding code we want to run. Listing 18-18 shows code | |
303 | responsible for managing a setting’s value. The business requirements are that | |
304 | the user should not be allowed to overwrite an existing customization of a | |
532ac7d7 | 305 | setting but can unset the setting and give it a value if it is currently unset. |
13cf67c4 XL |
306 | |
307 | ```rust | |
74b04a01 | 308 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-18/src/main.rs:here}} |
13cf67c4 XL |
309 | ``` |
310 | ||
311 | <span class="caption">Listing 18-18: Using an underscore within patterns that | |
312 | match `Some` variants when we don’t need to use the value inside the | |
313 | `Some`</span> | |
314 | ||
315 | This code will print `Can't overwrite an existing customized value` and then | |
316 | `setting is Some(5)`. In the first match arm, we don’t need to match on or use | |
317 | the values inside either `Some` variant, but we do need to test for the case | |
318 | when `setting_value` and `new_setting_value` are the `Some` variant. In that | |
923072b8 | 319 | case, we print the reason for not changing `setting_value`, and it doesn’t get |
13cf67c4 XL |
320 | changed. |
321 | ||
322 | In all other cases (if either `setting_value` or `new_setting_value` are | |
323 | `None`) expressed by the `_` pattern in the second arm, we want to allow | |
324 | `new_setting_value` to become `setting_value`. | |
325 | ||
326 | We can also use underscores in multiple places within one pattern to ignore | |
327 | particular values. Listing 18-19 shows an example of ignoring the second and | |
328 | fourth values in a tuple of five items. | |
329 | ||
330 | ```rust | |
74b04a01 | 331 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-19/src/main.rs:here}} |
13cf67c4 XL |
332 | ``` |
333 | ||
334 | <span class="caption">Listing 18-19: Ignoring multiple parts of a tuple</span> | |
335 | ||
336 | This code will print `Some numbers: 2, 8, 32`, and the values 4 and 16 will be | |
337 | ignored. | |
338 | ||
339 | #### Ignoring an Unused Variable by Starting Its Name with `_` | |
340 | ||
341 | If you create a variable but don’t use it anywhere, Rust will usually issue a | |
923072b8 FG |
342 | warning because an unused variable could be a bug. However, sometimes it’s |
343 | useful to be able to create a variable you won’t use yet, such as when you’re | |
344 | prototyping or just starting a project. In this situation, you can tell Rust | |
345 | not to warn you about the unused variable by starting the name of the variable | |
346 | with an underscore. In Listing 18-20, we create two unused variables, but when | |
347 | we compile this code, we should only get a warning about one of them. | |
13cf67c4 XL |
348 | |
349 | <span class="filename">Filename: src/main.rs</span> | |
350 | ||
351 | ```rust | |
74b04a01 | 352 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-20/src/main.rs}} |
13cf67c4 XL |
353 | ``` |
354 | ||
355 | <span class="caption">Listing 18-20: Starting a variable name with an | |
356 | underscore to avoid getting unused variable warnings</span> | |
357 | ||
358 | Here we get a warning about not using the variable `y`, but we don’t get a | |
923072b8 | 359 | warning about not using `_x`. |
13cf67c4 XL |
360 | |
361 | Note that there is a subtle difference between using only `_` and using a name | |
362 | that starts with an underscore. The syntax `_x` still binds the value to the | |
363 | variable, whereas `_` doesn’t bind at all. To show a case where this | |
364 | distinction matters, Listing 18-21 will provide us with an error. | |
365 | ||
366 | ```rust,ignore,does_not_compile | |
74b04a01 | 367 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-21/src/main.rs:here}} |
13cf67c4 XL |
368 | ``` |
369 | ||
370 | <span class="caption">Listing 18-21: An unused variable starting with an | |
371 | underscore still binds the value, which might take ownership of the value</span> | |
372 | ||
373 | We’ll receive an error because the `s` value will still be moved into `_s`, | |
374 | which prevents us from using `s` again. However, using the underscore by itself | |
375 | doesn’t ever bind to the value. Listing 18-22 will compile without any errors | |
376 | because `s` doesn’t get moved into `_`. | |
377 | ||
378 | ```rust | |
74b04a01 | 379 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-22/src/main.rs:here}} |
13cf67c4 XL |
380 | ``` |
381 | ||
382 | <span class="caption">Listing 18-22: Using an underscore does not bind the | |
383 | value</span> | |
384 | ||
385 | This code works just fine because we never bind `s` to anything; it isn’t moved. | |
386 | ||
387 | #### Ignoring Remaining Parts of a Value with `..` | |
388 | ||
923072b8 | 389 | With values that have many parts, we can use the `..` syntax to use specific |
13cf67c4 XL |
390 | parts and ignore the rest, avoiding the need to list underscores for each |
391 | ignored value. The `..` pattern ignores any parts of a value that we haven’t | |
392 | explicitly matched in the rest of the pattern. In Listing 18-23, we have a | |
393 | `Point` struct that holds a coordinate in three-dimensional space. In the | |
394 | `match` expression, we want to operate only on the `x` coordinate and ignore | |
395 | the values in the `y` and `z` fields. | |
396 | ||
397 | ```rust | |
74b04a01 | 398 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-23/src/main.rs:here}} |
13cf67c4 XL |
399 | ``` |
400 | ||
401 | <span class="caption">Listing 18-23: Ignoring all fields of a `Point` except | |
402 | for `x` by using `..`</span> | |
403 | ||
404 | We list the `x` value and then just include the `..` pattern. This is quicker | |
405 | than having to list `y: _` and `z: _`, particularly when we’re working with | |
406 | structs that have lots of fields in situations where only one or two fields are | |
407 | relevant. | |
408 | ||
409 | The syntax `..` will expand to as many values as it needs to be. Listing 18-24 | |
410 | shows how to use `..` with a tuple. | |
411 | ||
412 | <span class="filename">Filename: src/main.rs</span> | |
413 | ||
414 | ```rust | |
74b04a01 | 415 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-24/src/main.rs}} |
13cf67c4 XL |
416 | ``` |
417 | ||
418 | <span class="caption">Listing 18-24: Matching only the first and last values in | |
419 | a tuple and ignoring all other values</span> | |
420 | ||
421 | In this code, the first and last value are matched with `first` and `last`. The | |
422 | `..` will match and ignore everything in the middle. | |
423 | ||
424 | However, using `..` must be unambiguous. If it is unclear which values are | |
425 | intended for matching and which should be ignored, Rust will give us an error. | |
426 | Listing 18-25 shows an example of using `..` ambiguously, so it will not | |
427 | compile. | |
428 | ||
429 | <span class="filename">Filename: src/main.rs</span> | |
430 | ||
431 | ```rust,ignore,does_not_compile | |
74b04a01 | 432 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-25/src/main.rs}} |
13cf67c4 XL |
433 | ``` |
434 | ||
435 | <span class="caption">Listing 18-25: An attempt to use `..` in an ambiguous | |
436 | way</span> | |
437 | ||
438 | When we compile this example, we get this error: | |
439 | ||
f035d41b | 440 | ```console |
74b04a01 | 441 | {{#include ../listings/ch18-patterns-and-matching/listing-18-25/output.txt}} |
13cf67c4 XL |
442 | ``` |
443 | ||
444 | It’s impossible for Rust to determine how many values in the tuple to ignore | |
445 | before matching a value with `second` and then how many further values to | |
446 | ignore thereafter. This code could mean that we want to ignore `2`, bind | |
447 | `second` to `4`, and then ignore `8`, `16`, and `32`; or that we want to ignore | |
448 | `2` and `4`, bind `second` to `8`, and then ignore `16` and `32`; and so forth. | |
449 | The variable name `second` doesn’t mean anything special to Rust, so we get a | |
450 | compiler error because using `..` in two places like this is ambiguous. | |
451 | ||
452 | ### Extra Conditionals with Match Guards | |
453 | ||
923072b8 FG |
454 | A *match guard* is an additional `if` condition, specified after the pattern in |
455 | a `match` arm, that must also match for that arm to be chosen. Match guards are | |
456 | useful for expressing more complex ideas than a pattern alone allows. | |
13cf67c4 XL |
457 | |
458 | The condition can use variables created in the pattern. Listing 18-26 shows a | |
459 | `match` where the first arm has the pattern `Some(x)` and also has a match | |
5099ac24 | 460 | guard of `if x % 2 == 0` (which will be true if the number is even). |
13cf67c4 XL |
461 | |
462 | ```rust | |
74b04a01 | 463 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-26/src/main.rs:here}} |
13cf67c4 XL |
464 | ``` |
465 | ||
466 | <span class="caption">Listing 18-26: Adding a match guard to a pattern</span> | |
467 | ||
5099ac24 | 468 | This example will print `The number 4 is even`. When `num` is compared to the |
13cf67c4 | 469 | pattern in the first arm, it matches, because `Some(4)` matches `Some(x)`. Then |
5099ac24 FG |
470 | the match guard checks whether the remainder of dividing `x` by 2 is equal to |
471 | 0, and because it is, the first arm is selected. | |
472 | ||
473 | If `num` had been `Some(5)` instead, the match guard in the first arm would | |
474 | have been false because the remainder of 5 divided by 2 is 1, which is not | |
475 | equal to 0. Rust would then go to the second arm, which would match because the | |
476 | second arm doesn’t have a match guard and therefore matches any `Some` variant. | |
477 | ||
478 | There is no way to express the `if x % 2 == 0` condition within a pattern, so | |
479 | the match guard gives us the ability to express this logic. The downside of | |
480 | this additional expressiveness is that the compiler doesn't try to check for | |
481 | exhaustiveness when match guard expressions are involved. | |
13cf67c4 XL |
482 | |
483 | In Listing 18-11, we mentioned that we could use match guards to solve our | |
923072b8 | 484 | pattern-shadowing problem. Recall that we created a new variable inside the |
13cf67c4 XL |
485 | pattern in the `match` expression instead of using the variable outside the |
486 | `match`. That new variable meant we couldn’t test against the value of the | |
9fa01778 | 487 | outer variable. Listing 18-27 shows how we can use a match guard to fix this |
13cf67c4 XL |
488 | problem. |
489 | ||
490 | <span class="filename">Filename: src/main.rs</span> | |
491 | ||
492 | ```rust | |
74b04a01 | 493 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-27/src/main.rs}} |
13cf67c4 XL |
494 | ``` |
495 | ||
496 | <span class="caption">Listing 18-27: Using a match guard to test for equality | |
497 | with an outer variable</span> | |
498 | ||
499 | This code will now print `Default case, x = Some(5)`. The pattern in the second | |
500 | match arm doesn’t introduce a new variable `y` that would shadow the outer `y`, | |
501 | meaning we can use the outer `y` in the match guard. Instead of specifying the | |
502 | pattern as `Some(y)`, which would have shadowed the outer `y`, we specify | |
503 | `Some(n)`. This creates a new variable `n` that doesn’t shadow anything because | |
504 | there is no `n` variable outside the `match`. | |
505 | ||
506 | The match guard `if n == y` is not a pattern and therefore doesn’t introduce | |
507 | new variables. This `y` *is* the outer `y` rather than a new shadowed `y`, and | |
508 | we can look for a value that has the same value as the outer `y` by comparing | |
509 | `n` to `y`. | |
510 | ||
511 | You can also use the *or* operator `|` in a match guard to specify multiple | |
512 | patterns; the match guard condition will apply to all the patterns. Listing | |
923072b8 FG |
513 | 18-28 shows the precedence when combining a pattern that uses `|` with a match |
514 | guard. The important part of this example is that the `if y` match guard | |
515 | applies to `4`, `5`, *and* `6`, even though it might look like `if y` only | |
516 | applies to `6`. | |
13cf67c4 XL |
517 | |
518 | ```rust | |
74b04a01 | 519 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-28/src/main.rs:here}} |
13cf67c4 XL |
520 | ``` |
521 | ||
9fa01778 | 522 | <span class="caption">Listing 18-28: Combining multiple patterns with a match |
13cf67c4 XL |
523 | guard</span> |
524 | ||
525 | The match condition states that the arm only matches if the value of `x` is | |
526 | equal to `4`, `5`, or `6` *and* if `y` is `true`. When this code runs, the | |
527 | pattern of the first arm matches because `x` is `4`, but the match guard `if y` | |
528 | is false, so the first arm is not chosen. The code moves on to the second arm, | |
529 | which does match, and this program prints `no`. The reason is that the `if` | |
530 | condition applies to the whole pattern `4 | 5 | 6`, not only to the last value | |
531 | `6`. In other words, the precedence of a match guard in relation to a pattern | |
532 | behaves like this: | |
533 | ||
534 | ```text | |
535 | (4 | 5 | 6) if y => ... | |
536 | ``` | |
537 | ||
538 | rather than this: | |
539 | ||
540 | ```text | |
541 | 4 | 5 | (6 if y) => ... | |
542 | ``` | |
543 | ||
544 | After running the code, the precedence behavior is evident: if the match guard | |
545 | were applied only to the final value in the list of values specified using the | |
546 | `|` operator, the arm would have matched and the program would have printed | |
547 | `yes`. | |
548 | ||
549 | ### `@` Bindings | |
550 | ||
923072b8 FG |
551 | The *at* operator `@` lets us create a variable that holds a value at the same |
552 | time as we’re testing that value for a pattern match. In Listing 18-29, we want | |
553 | to test that a `Message::Hello` `id` field is within the range `3..=7`. We also | |
554 | want to bind the value to the variable `id_variable` so we can use it in the | |
555 | code associated with the arm. We could name this variable `id`, the same as the | |
556 | field, but for this example we’ll use a different name. | |
13cf67c4 XL |
557 | |
558 | ```rust | |
74b04a01 | 559 | {{#rustdoc_include ../listings/ch18-patterns-and-matching/listing-18-29/src/main.rs:here}} |
13cf67c4 XL |
560 | ``` |
561 | ||
9fa01778 | 562 | <span class="caption">Listing 18-29: Using `@` to bind to a value in a pattern |
13cf67c4 XL |
563 | while also testing it</span> |
564 | ||
565 | This example will print `Found an id in range: 5`. By specifying `id_variable | |
e1599b0c | 566 | @` before the range `3..=7`, we’re capturing whatever value matched the range |
13cf67c4 XL |
567 | while also testing that the value matched the range pattern. |
568 | ||
569 | In the second arm, where we only have a range specified in the pattern, the code | |
570 | associated with the arm doesn’t have a variable that contains the actual value | |
571 | of the `id` field. The `id` field’s value could have been 10, 11, or 12, but | |
572 | the code that goes with that pattern doesn’t know which it is. The pattern code | |
573 | isn’t able to use the value from the `id` field, because we haven’t saved the | |
574 | `id` value in a variable. | |
575 | ||
576 | In the last arm, where we’ve specified a variable without a range, we do have | |
577 | the value available to use in the arm’s code in a variable named `id`. The | |
578 | reason is that we’ve used the struct field shorthand syntax. But we haven’t | |
579 | applied any test to the value in the `id` field in this arm, as we did with the | |
580 | first two arms: any value would match this pattern. | |
581 | ||
582 | Using `@` lets us test a value and save it in a variable within one pattern. | |
583 | ||
13cf67c4 XL |
584 | ## Summary |
585 | ||
923072b8 FG |
586 | Rust’s patterns are very useful in distinguishing between different kinds of |
587 | data. When used in `match` expressions, Rust ensures your patterns cover every | |
588 | possible value, or your program won’t compile. Patterns in `let` statements and | |
589 | function parameters make those constructs more useful, enabling the | |
590 | destructuring of values into smaller parts at the same time as assigning to | |
13cf67c4 XL |
591 | variables. We can create simple or complex patterns to suit our needs. |
592 | ||
593 | Next, for the penultimate chapter of the book, we’ll look at some advanced | |
594 | aspects of a variety of Rust’s features. |