]> git.proxmox.com Git - rustc.git/blame - src/doc/book/src/ch18-03-pattern-syntax.md
New upstream version 1.38.0+dfsg1
[rustc.git] / src / doc / book / src / ch18-03-pattern-syntax.md
CommitLineData
13cf67c4
XL
1## Pattern Syntax
2
3Throughout the book, you’ve seen examples of many kinds of patterns. In this
4section, we gather all the syntax valid in patterns and discuss why you might
5want to use each one.
6
7### Matching Literals
8
9As you saw in Chapter 6, you can match patterns against literals directly. The
10following code gives some examples:
11
12```rust
13let x = 1;
14
15match x {
16 1 => println!("one"),
17 2 => println!("two"),
18 3 => println!("three"),
19 _ => println!("anything"),
20}
21```
22
23This code prints `one` because the value in `x` is 1. This syntax is useful
24when you want your code to take an action if it gets a particular concrete
25value.
26
27### Matching Named Variables
28
29Named variables are irrefutable patterns that match any value, and we’ve used
30them many times in the book. However, there is a complication when you use
31named variables in `match` expressions. Because `match` starts a new scope,
32variables declared as part of a pattern inside the `match` expression will
33shadow those with the same name outside the `match` construct, as is the case
34with all variables. In Listing 18-11, we declare a variable named `x` with the
35value `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
38running this code or reading further.
39
40<span class="filename">Filename: src/main.rs</span>
41
42```rust
43fn 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
58introduces a shadowed variable `y`</span>
59
60Let’s walk through what happens when the `match` expression runs. The pattern
61in the first match arm doesn’t match the defined value of `x`, so the code
62continues.
63
64The pattern in the second match arm introduces a new variable named `y` that
65will match any value inside a `Some` value. Because we’re in a new scope inside
66the `match` expression, this is a new `y` variable, not the `y` we declared at
67the beginning with the value 10. This new `y` binding will match any value
68inside a `Some`, which is what we have in `x`. Therefore, this new `y` binds to
69the inner value of the `Some` in `x`. That value is `5`, so the expression for
70that arm executes and prints `Matched, y = 5`.
71
72If `x` had been a `None` value instead of `Some(5)`, the patterns in the first
73two arms wouldn’t have matched, so the value would have matched to the
74underscore. We didn’t introduce the `x` variable in the pattern of the
75underscore arm, so the `x` in the expression is still the outer `x` that hasn’t
76been shadowed. In this hypothetical case, the `match` would print `Default
77case, x = None`.
78
79When the `match` expression is done, its scope ends, and so does the scope of
80the inner `y`. The last `println!` produces `at the end: x = Some(5), y = 10`.
81
82To 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
84guard conditional instead. We’ll talk about match guards later in the [“Extra
85Conditionals with Match Guards”](#extra-conditionals-with-match-guards)<!--
86ignore --> section.
13cf67c4
XL
87
88### Multiple Patterns
89
90In `match` expressions, you can match multiple patterns using the `|` syntax,
91which means *or*. For example, the following code matches the value of `x`
92against the match arms, the first of which has an *or* option, meaning if the
93value of `x` matches either of the values in that arm, that arm’s code will
94run:
95
96```rust
97let x = 1;
98
99match x {
100 1 | 2 => println!("one or two"),
101 3 => println!("three"),
102 _ => println!("anything"),
103}
104```
105
106This code prints `one or two`.
107
108### Matching Ranges of Values with `...`
109
110The `...` syntax allows us to match to an inclusive range of values. In the
111following code, when a pattern matches any of the values within the range, that
112arm will execute:
113
114```rust
115let x = 5;
116
117match x {
48663c56 118 1...5 => println!("one through five"),
13cf67c4
XL
119 _ => println!("something else"),
120}
121```
122
123If `x` is 1, 2, 3, 4, or 5, the first arm will match. This syntax is more
48663c56
XL
124convenient 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 `|`.
126Specifying a range is much shorter, especially if we want to match, say, any
127number between 1 and 1,000!
13cf67c4
XL
128
129Ranges are only allowed with numeric values or `char` values, because the
130compiler checks that the range isn’t empty at compile time. The only types for
131which Rust can tell if a range is empty or not are `char` and numeric values.
132
133Here is an example using ranges of `char` values:
134
135```rust
136let x = 'c';
137
138match 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
145Rust can tell that `c` is within the first pattern’s range and prints `early
146ASCII letter`.
147
148### Destructuring to Break Apart Values
149
150We can also use patterns to destructure structs, enums, tuples, and references
151to use different parts of these values. Let’s walk through each value.
152
153#### Destructuring Structs
154
155Listing 18-12 shows a `Point` struct with two fields, `x` and `y`, that we can
156break apart using a pattern with a `let` statement.
157
158<span class="filename">Filename: src/main.rs</span>
159
160```rust
161struct Point {
162 x: i32,
163 y: i32,
164}
165
166fn 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
176separate variables</span>
177
178This code creates the variables `a` and `b` that match the values of the `x`
69743fb6 179and `y` fields of the `p` struct. This example shows that the names of the
13cf67c4
XL
180variables in the pattern don’t have to match the field names of the struct. But
181it’s common to want the variable names to match the field names to make it
182easier to remember which variables came from which fields.
183
184Because 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
186shorthand for patterns that match struct fields: you only need to list the name
187of the struct field, and the variables created from the pattern will have the
188same names. Listing 18-13 shows code that behaves in the same way as the code
189in 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
195struct Point {
196 x: i32,
197 y: i32,
198}
199
200fn 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
210field shorthand</span>
211
212This code creates the variables `x` and `y` that match the `x` and `y` fields
213of the `p` variable. The outcome is that the variables `x` and `y` contain the
214values from the `p` struct.
215
216We can also destructure with literal values as part of the struct pattern
217rather than creating variables for all the fields. Doing so allows us to test
218some of the fields for particular values while creating variables to
219destructure the other fields.
220
221Listing 18-14 shows a `match` expression that separates `Point` values into
222three cases: points that lie directly on the `x` axis (which is true when `y =
2230`), 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#
233fn 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
245in one pattern</span>
246
247The first arm will match any point that lies on the `x` axis by specifying that
248the `y` field matches if its value matches the literal `0`. The pattern still
249creates an `x` variable that we can use in the code for this arm.
250
251Similarly, the second arm matches any point on the `y` axis by specifying that
252the `x` field matches if its value is `0` and creates a variable `y` for the
253value of the `y` field. The third arm doesn’t specify any literals, so it
254matches any other `Point` and creates variables for both the `x` and `y` fields.
255
256In this example, the value `p` matches the second arm by virtue of `x`
257containing a 0, so this code will print `On the y axis at 7`.
258
259#### Destructuring Enums
260
261We’ve destructured enums earlier in this book, for example, when we
262destructured `Option<i32>` in Listing 6-5 in Chapter 6. One detail we haven’t
263mentioned explicitly is that the pattern to destructure an enum should
264correspond to the way the data stored within the enum is defined. As an
265example, in Listing 18-15 we use the `Message` enum from Listing 6-2 and write
266a `match` with patterns that will destructure each inner value.
267
268<span class="filename">Filename: src/main.rs</span>
269
270```rust
271enum Message {
272 Quit,
273 Move { x: i32, y: i32 },
274 Write(String),
275 ChangeColor(i32, i32, i32),
276}
277
278fn 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
306different kinds of values</span>
307
308This code will print `Change the color to red 0, green 160, and blue 255`. Try
309changing the value of `msg` to see the code from the other arms run.
310
311For enum variants without any data, like `Message::Quit`, we can’t destructure
312the value any further. We can only match on the literal `Message::Quit` value,
313and no variables are in that pattern.
314
315For struct-like enum variants, such as `Message::Move`, we can use a pattern
316similar to the pattern we specify to match structs. After the variant name, we
317place curly brackets and then list the fields with variables so we break apart
318the pieces to use in the code for this arm. Here we use the shorthand form as
319we did in Listing 18-13.
320
321For tuple-like enum variants, like `Message::Write` that holds a tuple with one
322element and `Message::ChangeColor` that holds a tuple with three elements, the
323pattern is similar to the pattern we specify to match tuples. The number of
324variables in the pattern must match the number of elements in the variant we’re
325matching.
326
9fa01778 327#### Destructuring Nested Structs and Enums
13cf67c4 328
532ac7d7
XL
329Until now, all our examples have been matching structs or enums that were one
330level deep. Matching can work on nested items too!
13cf67c4 331
532ac7d7
XL
332For example, we can refactor the code in Listing 18-15 to support RGB and HSV
333colors in the `ChangeColor` message, as shown in Listing 18-16.
13cf67c4
XL
334
335```rust
336enum Color {
337 Rgb(i32, i32, i32),
48663c56 338 Hsv(i32, i32, i32),
13cf67c4
XL
339}
340
341enum Message {
342 Quit,
343 Move { x: i32, y: i32 },
344 Write(String),
345 ChangeColor(Color),
346}
347
348fn 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 375The 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
377the pattern binds to the three inner `i32` values. The pattern of the second
378arm also matches a `Message::ChangeColor` enum variant, but the inner enum
379matches the `Color::Hsv` variant instead. We can specify these complex
380conditions in one `match` expression, even though two enums are involved.
13cf67c4
XL
381
382#### Destructuring Structs and Tuples
383
384We can mix, match, and nest destructuring patterns in even more complex ways.
385The following example shows a complicated destructure where we nest structs and
386tuples inside a tuple and destructure all the primitive values out:
387
388```rust
389# struct Point {
390# x: i32,
391# y: i32,
392# }
393#
394let ((feet, inches), Point {x, y}) = ((3, 10), Point { x: 3, y: -10 });
395```
396
397This code lets us break complex types into their component parts so we can use
398the values we’re interested in separately.
399
400Destructuring with patterns is a convenient way to use pieces of values, such
401as the value from each field in a struct, separately from each other.
402
403### Ignoring Values in a Pattern
404
405You’ve seen that it’s sometimes useful to ignore values in a pattern, such as
406in the last arm of a `match`, to get a catchall that doesn’t actually do
407anything but does account for all remaining possible values. There are a few
408ways to ignore entire values or parts of values in a pattern: using the `_`
409pattern (which you’ve seen), using the `_` pattern within another pattern,
410using a name that starts with an underscore, or using `..` to ignore remaining
411parts of a value. Let’s explore how and why to use each of these patterns.
412
413#### Ignoring an Entire Value with `_`
414
415We’ve used the underscore (`_`) as a wildcard pattern that will match any value
416but not bind to the value. Although the underscore `_` pattern is especially
417useful as the last arm in a `match` expression, we can use it in any pattern,
418including function parameters, as shown in Listing 18-17.
419
420<span class="filename">Filename: src/main.rs</span>
421
422```rust
423fn foo(_: i32, y: i32) {
424 println!("This code only uses the y parameter: {}", y);
425}
426
427fn main() {
428 foo(3, 4);
429}
430```
431
432<span class="caption">Listing 18-17: Using `_` in a function signature</span>
433
434This code will completely ignore the value passed as the first argument, `3`,
435and will print `This code only uses the y parameter: 4`.
436
437In most cases when you no longer need a particular function parameter, you
438would change the signature so it doesn’t include the unused parameter. Ignoring
439a function parameter can be especially useful in some cases, for example, when
440implementing a trait when you need a certain type signature but the function
441body in your implementation doesn’t need one of the parameters. The compiler
442will then not warn about unused function parameters, as it would if you used a
443name instead.
444
445#### Ignoring Parts of a Value with a Nested `_`
446
447We can also use `_` inside another pattern to ignore just part of a value, for
448example, when we want to test for only part of a value but have no use for the
449other parts in the corresponding code we want to run. Listing 18-18 shows code
450responsible for managing a setting’s value. The business requirements are that
451the user should not be allowed to overwrite an existing customization of a
532ac7d7 452setting but can unset the setting and give it a value if it is currently unset.
13cf67c4
XL
453
454```rust
455let mut setting_value = Some(5);
456let new_setting_value = Some(10);
457
458match (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
467println!("setting is {:?}", setting_value);
468```
469
470<span class="caption">Listing 18-18: Using an underscore within patterns that
471match `Some` variants when we don’t need to use the value inside the
472`Some`</span>
473
474This 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
476the values inside either `Some` variant, but we do need to test for the case
477when `setting_value` and `new_setting_value` are the `Some` variant. In that
478case, we print why we’re not changing `setting_value`, and it doesn’t get
479changed.
480
481In 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
485We can also use underscores in multiple places within one pattern to ignore
486particular values. Listing 18-19 shows an example of ignoring the second and
487fourth values in a tuple of five items.
488
489```rust
490let numbers = (2, 4, 8, 16, 32);
491
492match 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
501This code will print `Some numbers: 2, 8, 32`, and the values 4 and 16 will be
502ignored.
503
504#### Ignoring an Unused Variable by Starting Its Name with `_`
505
506If you create a variable but don’t use it anywhere, Rust will usually issue a
507warning because that could be a bug. But sometimes it’s useful to create a
508variable you won’t use yet, such as when you’re prototyping or just starting a
509project. In this situation, you can tell Rust not to warn you about the unused
510variable by starting the name of the variable with an underscore. In Listing
51118-20, we create two unused variables, but when we run this code, we should
512only get a warning about one of them.
513
514<span class="filename">Filename: src/main.rs</span>
515
516```rust
517fn 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
524underscore to avoid getting unused variable warnings</span>
525
526Here we get a warning about not using the variable `y`, but we don’t get a
527warning about not using the variable preceded by the underscore.
528
529Note that there is a subtle difference between using only `_` and using a name
530that starts with an underscore. The syntax `_x` still binds the value to the
531variable, whereas `_` doesn’t bind at all. To show a case where this
532distinction matters, Listing 18-21 will provide us with an error.
533
534```rust,ignore,does_not_compile
535let s = Some(String::from("Hello!"));
536
537if let Some(_s) = s {
538 println!("found a string");
539}
540
541println!("{:?}", s);
542```
543
544<span class="caption">Listing 18-21: An unused variable starting with an
545underscore still binds the value, which might take ownership of the value</span>
546
547We’ll receive an error because the `s` value will still be moved into `_s`,
548which prevents us from using `s` again. However, using the underscore by itself
549doesn’t ever bind to the value. Listing 18-22 will compile without any errors
550because `s` doesn’t get moved into `_`.
551
552```rust
553let s = Some(String::from("Hello!"));
554
555if let Some(_) = s {
556 println!("found a string");
557}
558
559println!("{:?}", s);
560```
561
562<span class="caption">Listing 18-22: Using an underscore does not bind the
563value</span>
564
565This 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
569With values that have many parts, we can use the `..` syntax to use only a few
570parts and ignore the rest, avoiding the need to list underscores for each
571ignored value. The `..` pattern ignores any parts of a value that we haven’t
572explicitly 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
575the values in the `y` and `z` fields.
576
577```rust
578struct Point {
579 x: i32,
580 y: i32,
581 z: i32,
582}
583
584let origin = Point { x: 0, y: 0, z: 0 };
585
586match 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
592for `x` by using `..`</span>
593
594We list the `x` value and then just include the `..` pattern. This is quicker
595than having to list `y: _` and `z: _`, particularly when we’re working with
596structs that have lots of fields in situations where only one or two fields are
597relevant.
598
599The syntax `..` will expand to as many values as it needs to be. Listing 18-24
600shows how to use `..` with a tuple.
601
602<span class="filename">Filename: src/main.rs</span>
603
604```rust
605fn 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
617a tuple and ignoring all other values</span>
618
619In this code, the first and last value are matched with `first` and `last`. The
620`..` will match and ignore everything in the middle.
621
622However, using `..` must be unambiguous. If it is unclear which values are
623intended for matching and which should be ignored, Rust will give us an error.
624Listing 18-25 shows an example of using `..` ambiguously, so it will not
625compile.
626
627<span class="filename">Filename: src/main.rs</span>
628
629```rust,ignore,does_not_compile
630fn 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
642way</span>
643
644When we compile this example, we get this error:
645
646```text
647error: `..` can only be used once per tuple or tuple struct pattern
648 --> src/main.rs:5:22
649 |
6505 | (.., second, ..) => {
651 | ^^
652```
653
654It’s impossible for Rust to determine how many values in the tuple to ignore
655before matching a value with `second` and then how many further values to
656ignore 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.
659The variable name `second` doesn’t mean anything special to Rust, so we get a
660compiler error because using `..` in two places like this is ambiguous.
661
662### Extra Conditionals with Match Guards
663
664A *match guard* is an additional `if` condition specified after the pattern in
665a `match` arm that must also match, along with the pattern matching, for that
666arm to be chosen. Match guards are useful for expressing more complex ideas
667than a pattern alone allows.
668
669The 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
671guard of `if x < 5`.
672
673```rust
674let num = Some(4);
675
676match 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
685This example will print `less than five: 4`. When `num` is compared to the
686pattern in the first arm, it matches, because `Some(4)` matches `Some(x)`. Then
687the match guard checks whether the value in `x` is less than `5`, and because
688it is, the first arm is selected.
689
690If `num` had been `Some(10)` instead, the match guard in the first arm would
691have been false because 10 is not less than 5. Rust would then go to the second
692arm, which would match because the second arm doesn’t have a match guard and
693therefore matches any `Some` variant.
694
695There is no way to express the `if x < 5` condition within a pattern, so the
696match guard gives us the ability to express this logic.
697
698In Listing 18-11, we mentioned that we could use match guards to solve our
699pattern-shadowing problem. Recall that a new variable was created inside the
700pattern 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 702outer variable. Listing 18-27 shows how we can use a match guard to fix this
13cf67c4
XL
703problem.
704
705<span class="filename">Filename: src/main.rs</span>
706
707```rust
708fn 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
723with an outer variable</span>
724
725This code will now print `Default case, x = Some(5)`. The pattern in the second
726match arm doesn’t introduce a new variable `y` that would shadow the outer `y`,
727meaning we can use the outer `y` in the match guard. Instead of specifying the
728pattern 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
730there is no `n` variable outside the `match`.
731
732The match guard `if n == y` is not a pattern and therefore doesn’t introduce
733new variables. This `y` *is* the outer `y` rather than a new shadowed `y`, and
734we can look for a value that has the same value as the outer `y` by comparing
735`n` to `y`.
736
737You can also use the *or* operator `|` in a match guard to specify multiple
738patterns; the match guard condition will apply to all the patterns. Listing
9fa01778 73918-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
741to `4`, `5`, *and* `6`, even though it might look like `if y` only applies to
742`6`.
743
744```rust
745let x = 4;
746let y = false;
747
748match 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
755guard</span>
756
757The match condition states that the arm only matches if the value of `x` is
758equal to `4`, `5`, or `6` *and* if `y` is `true`. When this code runs, the
759pattern of the first arm matches because `x` is `4`, but the match guard `if y`
760is false, so the first arm is not chosen. The code moves on to the second arm,
761which does match, and this program prints `no`. The reason is that the `if`
762condition 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
764behaves like this:
765
766```text
767(4 | 5 | 6) if y => ...
768```
769
770rather than this:
771
772```text
7734 | 5 | (6 if y) => ...
774```
775
776After running the code, the precedence behavior is evident: if the match guard
777were 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
783The *at* operator (`@`) lets us create a variable that holds a value at the
784same time we’re testing that value to see whether it matches a pattern. Listing
9fa01778 78518-29 shows an example where we want to test that a `Message::Hello` `id` field
13cf67c4
XL
786is 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
788name this variable `id`, the same as the field, but for this example we’ll use
789a different name.
790
791```rust
792enum Message {
793 Hello { id: i32 },
794}
795
796let msg = Message::Hello { id: 5 };
797
798match 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
812while also testing it</span>
813
814This 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
816while also testing that the value matched the range pattern.
817
818In the second arm, where we only have a range specified in the pattern, the code
819associated with the arm doesn’t have a variable that contains the actual value
820of the `id` field. The `id` field’s value could have been 10, 11, or 12, but
821the code that goes with that pattern doesn’t know which it is. The pattern code
822isn’t able to use the value from the `id` field, because we haven’t saved the
823`id` value in a variable.
824
825In the last arm, where we’ve specified a variable without a range, we do have
826the value available to use in the arm’s code in a variable named `id`. The
827reason is that we’ve used the struct field shorthand syntax. But we haven’t
828applied any test to the value in the `id` field in this arm, as we did with the
829first two arms: any value would match this pattern.
830
831Using `@` lets us test a value and save it in a variable within one pattern.
832
13cf67c4
XL
833## Summary
834
835Rust’s patterns are very useful in that they help distinguish between different
836kinds of data. When used in `match` expressions, Rust ensures your patterns
837cover every possible value, or your program won’t compile. Patterns in `let`
838statements and function parameters make those constructs more useful, enabling
839the destructuring of values into smaller parts at the same time as assigning to
840variables. We can create simple or complex patterns to suit our needs.
841
842Next, for the penultimate chapter of the book, we’ll look at some advanced
843aspects of a variety of Rust’s features.