]> git.proxmox.com Git - rustc.git/blame - src/doc/book/second-edition/src/ch18-03-pattern-syntax.md
New upstream version 1.19.0+dfsg1
[rustc.git] / src / doc / book / second-edition / src / ch18-03-pattern-syntax.md
CommitLineData
cc61c64b
XL
1## All the Pattern Syntax
2
3We've seen some examples of different kinds of patterns throughout the book.
4This section lists all the syntax valid in patterns and why you might want to
5use each of them.
6
7### Literals
8
9As we saw in Chapter 6, you can match against literals directly:
10
11```rust
12let x = 1;
13
14match x {
15 1 => println!("one"),
16 2 => println!("two"),
17 3 => println!("three"),
18 _ => println!("anything"),
19}
20```
21
22This prints `one` since the value in `x` is 1.
23
24### Named Variables
25
26Named variables are irrefutable patterns that match any value.
27
28As with all variables, variables declared as part of a pattern will shadow
29variables with the same name outside of the `match` construct since a `match`
30starts a new scope. In Listing 18-10, we declare a variable named `x` with the
31value `Some(5)` and a variable `y` with the value `10`. Then we have a `match`
32expression on the value `x`. Take a look at the patterns in the match arms and
33the `println!` at the end, and make a guess about what will be printed before
34running this code or reading further:
35
36<span class="filename">Filename: src/main.rs</span>
37
38```rust
39fn main() {
40 let x = Some(5);
41 let y = 10;
42
43 match x {
44 Some(50) => println!("Got 50"),
45 Some(y) => println!("Matched, y = {:?}", y),
46 _ => println!("Default case, x = {:?}", x),
47 }
48
49 println!("at the end: x = {:?}, y = {:?}", x, y);
50}
51```
52
53<span class="caption">Listing 18-10: A `match` statement with an arm that
54introduces a shadowed variable `y`</span>
55
56<!-- NEXT PARAGRAPH WRAPPED WEIRD INTENTIONALLY SEE #199 -->
57
58Let's walk through what happens when the `match` statement runs. The first
59match arm has the pattern `Some(50)`, and the value in `x` (`Some(5)`) does not
60match `Some(50)`, so we continue. In the second match arm, the pattern
61`Some(y)` introduces a new variable name `y` that will match any value inside a
62`Some` value. Because we're in a new scope inside the `match` expression, this
63is a new variable, not the `y` we declared at the beginning that has the
64value 10. The new `y` binding will match any value inside a `Some`, which is
65what we have in `x`, so we execute the expression for that arm and print
66`Matched, y = 5` since this `y` binds to the inner value of the `Some` in `x`,
67which is 5.
68
69If `x` had been a `None` value instead of `Some(5)`, we would have matched the
70underscore since the other two arms' patterns would not have matched. In the
71expression for that match arm, since we did not introduce an `x` variable in
72the pattern of the arm, this `x` is still the outer `x` that has not been
73shadowed. In this hypothetical case, the `match` would print `Default case, x =
74None`.
75
76Once the `match` expression is over, its scope ends, and so does the scope of
77the inner `y`. The last `println!` produces `at the end: x = Some(5), y = 10`.
78
79In order to make a `match` expression that compares the values of the outer `x`
80and `y` rather than introducing a shadowed variable, we would need to use a
81match guard conditional instead. We'll be talking about match guards later in
82this section.
83
84### Multiple patterns
85
86In `match` expressions only, you can match multiple patterns with `|`, which
87means *or*:
88
89```rust
90let x = 1;
91
92match x {
93 1 | 2 => println!("one or two"),
94 3 => println!("three"),
95 _ => println!("anything"),
96}
97```
98
99This prints `one or two`.
100
101### Matching Ranges of Values with `...`
102
103You can match an inclusive range of values with `...`:
104
105```rust
106let x = 5;
107
108match x {
109 1 ... 5 => println!("one through five"),
110 _ => println!("something else"),
111}
112```
113
114If `x` is 1, 2, 3, 4, or 5, the first arm will match.
115
116Ranges are only allowed with numeric values or `char` values. Here's an example
117using ranges of `char` values:
118
119```rust
120let x = 'c';
121
122match x {
123 'a' ... 'j' => println!("early ASCII letter"),
124 'k' ... 'z' => println!("late ASCII letter"),
125 _ => println!("something else"),
126}
127```
128
129This will print `early ASCII letter`.
130
131### Destructuring to Break Apart Values
132
133Patterns can be used to *destructure* structs, enums, tuples, and references.
134Destructuring means to break a value up into its component pieces. Listing
13518-11 shows a `Point` struct with two fields, `x` and `y`, that we can break
136apart by using a pattern with a `let` statement:
137
138<span class="filename">Filename: src/main.rs</span>
139
140```rust
141struct Point {
142 x: i32,
143 y: i32,
144}
145
146fn main() {
147 let p = Point { x: 0, y: 7 };
148
149 let Point { x, y } = p;
150 assert_eq!(0, x);
151 assert_eq!(7, y);
152}
153```
154
155<span class="caption">Listing 18-11: Destructuring using struct field
156shorthand</span>
157
158This creates the variables `x` and `y` that match the `x` and `y` of `p`. The
159names of the variables must match the names of the fields to use this
160shorthand. If we wanted to use names different than the variable names, we can
161specify `field_name: variable_name` in the pattern. In Listing 18-12, `a` will
162have the value in the `Point` instance's `x` field and `b` will have the value
163in the `y` field:
164
165<span class="filename">Filename: src/main.rs</span>
166
167```rust
168struct Point {
169 x: i32,
170 y: i32,
171}
172
173fn main() {
174 let p = Point { x: 0, y: 7 };
175
176 let Point { x: a, y: b } = p;
177 assert_eq!(0, a);
178 assert_eq!(7, b);
179}
180```
181
182<span class="caption">Listing 18-12: Destructuring struct fields into variables
183with different names than the fields</span>
184
185We can also use destructuring with literal values in order to test and use
186inner parts of a value. Listing 18-13 shows a `match` statement that determines
187whether a point lies directly on the `x` axis (which is true when `y = 0`), on
188the `y` axis (`x = 0`), or neither:
189
190```rust
191# struct Point {
192# x: i32,
193# y: i32,
194# }
195#
196fn main() {
197 let p = Point { x: 0, y: 7 };
198
199 match p {
200 Point { x, y: 0 } => println!("On the x axis at {}", x),
201 Point { x: 0, y } => println!("On the y axis at {}", y),
202 Point { x, y } => println!("On neither axis: ({}, {})", x, y),
203 }
204}
205```
206
207<span class="caption">Listing 18-13: Destructuring and matching literal values
208in one pattern</span>
209
210This will print `On the y axis at 7` since the value `p` matches the second arm
211by virtue of `x` having the value 0.
212
213We used destructuring on enums in Chapter 6, such as in Listing 6-5 where we
214destructured an `Option<i32>` using a `match` expression and added one to the
215inner value of the `Some` variant.
216
217When the value we're matching against a pattern contains a reference, we can
218specify a `&` in the pattern in order to separate the reference and the value.
219This is especially useful in closures used with iterators that iterate over
220references to values when we want to use the values in the closure rather than
221the references. Listing 18-14 shows how to iterate over references to `Point`
222instances in a vector, and destructure both the reference and the struct in
223order to be able to perform calculations on the `x` and `y` values easily:
224
225```rust
226# struct Point {
227# x: i32,
228# y: i32,
229# }
230#
231let points = vec![
232 Point { x: 0, y: 0 },
233 Point { x: 1, y: 5 },
234 Point { x: 10, y: -3 },
235];
236let sum_of_squares: i32 = points
237 .iter()
238 .map(|&Point {x, y}| x * x + y * y)
239 .sum();
240```
241
242<span class="caption">Listing 18-14: Destructuring a reference to a struct into
243the struct field values</span>
244
245Because `iter` iterates over references to the items in the vector, if we
246forgot the `&` in the closure arguments in the `map`, we'd get a type mismatch
247error like this:
248
249```text
250error[E0308]: mismatched types
251 -->
252 |
25314 | .map(|Point {x, y}| x * x + y * y)
254 | ^^^^^^^^^^^^ expected &Point, found struct `Point`
255 |
256 = note: expected type `&Point`
257 found type `Point`
258```
259
260This says Rust was expecting our closure to match `&Point`, but we tried to
261match the value with a pattern that was a `Point` value, not a reference to a
262`Point`.
263
264We can mix, match, and nest destructuring patterns in even more complex ways:
7cac9316 265we can do something complicated like this example where we nest structs and
cc61c64b
XL
266tuples inside of a tuple and destructure all the primitive values out:
267
268```rust
269# struct Point {
270# x: i32,
271# y: i32,
272# }
273#
274let ((feet, inches), Point {x, y}) = ((3, 10), Point { x: 3, y: -10 });
275```
276
277This lets us break complex types into their component parts.
278
279### Ignoring Values in a Pattern
280
281There are a few ways to ignore entire values or parts of values: using the `_`
282pattern, using the `_` pattern within another pattern, using a name that starts
283with an underscore, or using `..` to ignore all remaining parts of a value.
284Let's explore how and why to do each of these.
285
286#### Ignoring an Entire Value with `_`
287
288We've seen the use of underscore as a wildcard pattern that will match any value
289but not bind to the value. While the underscore pattern is especially useful as
290the last arm in a `match` expression, we can use it in any pattern, such as
291function arguments as shown in Listing 18-15:
292
293```rust
294fn foo(_: i32) {
295 // code goes here
296}
297```
298
299<span class="caption">Listing 18-15: Using `_` in a function signature</span>
300
301Normally, you would change the signature to not have the unused parameter. In
302cases such as implementing a trait, where you need a certain type signature,
303using an underscore lets you ignore a parameter, and the compiler won't warn
304about unused function parameters like it would if we had used a name instead.
305
306#### Ignoring Parts of a Value with a Nested `_`
307
308We can also use `_` inside of another pattern to ignore just part of a value.
309In Listing 18-16, the first `match` arm's pattern matches a `Some` value but
310ignores the value inside of the `Some` variant as specified by the underscore:
311
312```rust
313let x = Some(5);
314
315match x {
316 Some(_) => println!("got a Some and I don't care what's inside"),
317 None => (),
318}
319```
320
321<span class="caption">Listing 18-16: Ignoring the value inside of the `Some`
322variant by using a nested underscore</span>
323
324This is useful when the code associated with the `match` arm doesn't use the
325nested part of the variable at all.
326
327We can also use underscores in multiple places within one pattern, as shown in
328Listing 18-17 where we're ignoring the second and fourth values in a tuple of
329five items:
330
331```rust
332let numbers = (2, 4, 8, 16, 32);
333
334match numbers {
335 (first, _, third, _, fifth) => {
336 println!("Some numbers: {}, {}, {}", first, third, fifth)
337 },
338}
339```
340
341<span class="caption">Listing 18-17: Ignoring multiple parts of a tuple</span>
342
343This will print `Some numbers: 2, 8, 32`, and the values 4 and 16 will be
344ignored.
345
346#### Ignoring an Unused Variable by Starting its Name with an Underscore
347
348Usually, Rust will warn you if you create a variable but don't use it anywhere,
349since that could be a bug. If you're prototyping or just starting a project,
350though, you might create a variable that you'll use eventually, but temporarily
351it will be unused. If you're in this situation and would like to tell Rust not
352to warn you about the unused variable, you can start the name of the variable
353with an underscore. This works just like a variable name in any pattern, only
354Rust won't warn you if the variable goes unused. In Listing 18-18, we
355do get a warning about not using the variable `y`, but we don't get a warning
356about not using the variable `_x`:
357
358```rust
359fn main() {
360 let _x = 5;
361 let y = 10;
362}
363```
364
365<span class="caption">Listing 18-18: Starting a variable name with an underscore
366in order to not get unused variable warnings</span>
367
368Note that there is a subtle difference between using only `_` and using a name
369that starts with an underscore like `_x`: `_x` still binds the value to the
370variable, but `_` doesn't bind at all.
371
372Listing 18-19 shows a case where this distinction matters: `s` will still be
373moved into `_s`, which prevents us from using `s` again:
374
375```rust,ignore
376let s = Some(String::from("Hello!"));
377
378if let Some(_s) = s {
379 println!("found a string");
380}
381
382println!("{:?}", s);
383```
384
385<span class="caption">Listing 18-19: An unused variable starting with an
386underscore still binds the value, which may take ownership of the value</span>
387
388Using underscore by itself, however, doesn't ever bind to the value. Listing
38918-20 will compile without any errors since `s` does not get moved into `_`:
390
391```rust
392let s = Some(String::from("Hello!"));
393
394if let Some(_) = s {
395 println!("found a string");
396}
397
398println!("{:?}", s);
399```
400
401<span class="caption">Listing 18-20: Using underscore does not bind the
402value</span>
403
404This works just fine. Because we never bind `s` to anything, it's not moved.
405
406#### Ignoring Remaining Parts of a Value with `..`
407
408With values that have many parts, we can extract only a few parts and avoid
409having to list underscores for each remaining part by instead using `..`. The
410`..` pattern will ignore any parts of a value that we haven't explicitly
411matched in the rest of the pattern. In Listing 18-21, we have a `Point` struct
412that holds a coordinate in three dimensional space. In the `match` expression,
413we only want to operate on the `x` coordinate and ignore the values in the `y`
414and `z` fields:
415
416```rust
417struct Point {
418 x: i32,
419 y: i32,
420 z: i32,
421}
422
423let origin = Point { x: 0, y: 0, z: 0 };
424
425match origin {
426 Point { x, .. } => println!("x is {}", x),
427}
428```
429
430<span class="caption">Listing 18-21: Ignoring all fields of a `Point` except
431for `x` by using `..`</span>
432
433Using `..` is shorter to type than having to list out `y: _` and `z: _`. The
434`..` pattern is especially useful when working with structs that have lots of
435fields in situations where only one or two fields are relevant.
436
437`..` will expand to as many values as it needs to be. Listing 18-22 shows a use
438of `..` with a tuple:
439
440```rust
441fn main() {
442 let numbers = (2, 4, 8, 16, 32);
443
444 match numbers {
445 (first, .., last) => {
446 println!("Some numbers: {}, {}", first, last);
447 },
448 }
449}
450```
451
452<span class="caption">Listing 18-22: Matching only the first and last values in
453a tuple and ignoring all other values with `..`</span>
454
455Here, we have the first and last value matched, with `first` and `last`. The
456`..` will match and ignore all of the things in the middle.
457
458Using `..` must be unambiguous, however. Listing 18-23 shows an example where
459it's not clear to Rust which values we want to match and which values we want
460to ignore:
461
462```rust,ignore
463fn main() {
464 let numbers = (2, 4, 8, 16, 32);
465
466 match numbers {
467 (.., second, ..) => {
468 println!("Some numbers: {}", second)
469 },
470 }
471}
472```
473
474<span class="caption">Listing 18-23: An attempt to use `..` in a way that is
475ambiguous</span>
476
477If we compile this example, we get this error:
478
479```text
480error: `..` can only be used once per tuple or tuple struct pattern
481 --> src/main.rs:5:22
482 |
4835 | (.., second, ..) => {
484 | ^^
485```
486
487It's not possible to determine how many values in the tuple should be ignored
488before one value is matched with `second`, and then how many further values are
489ignored after that. We could mean that we want to ignore 2, bind `second` to 4,
490then ignore 8, 16, and 32, or we could mean that we want to ignore 2 and 4,
491bind `second` to 8, then ignore 16 and 32, and so forth. The variable name
492`second` doesn't mean anything special to Rust, so we get a compiler error
493since using `..` in two places like this is ambiguous.
494
495### `ref` and `ref mut` to Create References in Patterns
496
497Usually, when you match against a pattern, the variables that the pattern
498introduces are bound to a value. This means you'll end up moving the value into
499the `match` (or wherever you're using the pattern) since the ownership rules
500apply. Listing 18-24 shows an example:
501
502```rust,ignore
503let robot_name = Some(String::from("Bors"));
504
505match robot_name {
506 Some(name) => println!("Found a name: {}", name),
507 None => (),
508}
509
510println!("robot_name is: {:?}", robot_name);
511```
512
513<span class="caption">Listing 18-24: Creating a variable in a match arm pattern
514takes ownership of the value</span>
515
516This example will fail to compile since the value inside the `Some` value in
517`robot_name` is moved within the `match` when `name` binds to that value.
518
519Using `&` in a pattern matches an existing reference in the value, as we saw in
520the "Destructuring to Break Apart Values" section. If you want to create a
521reference instead in order to borrow the value in a pattern variable, use the
522`ref` keyword before the new variable, as shown in Listing 18-25:
523
524```rust
525let robot_name = Some(String::from("Bors"));
526
527match robot_name {
528 Some(ref name) => println!("Found a name: {}", name),
529 None => (),
530}
531
532println!("robot_name is: {:?}", robot_name);
533```
534
535<span class="caption">Listing 18-25: Creating a reference so that a pattern
536variable does not take ownership of a value</span>
537
538This example will compile because the value in the `Some` variant in
539`robot_name` is not moved into the `Some(ref name)` arm of the match; the match
540only took a reference to the data in `robot_name` rather than moving it.
541
542To create a mutable reference, use `ref mut` for the same reason as shown in
543Listing 18-26:
544
545```rust
546let mut robot_name = Some(String::from("Bors"));
547
548match robot_name {
549 Some(ref mut name) => *name = String::from("Another name"),
550 None => (),
551}
552
553println!("robot_name is: {:?}", robot_name);
554```
555
556<span class="caption">Listing 18-26: Creating a mutable reference to a value as
557part of a pattern using `ref mut`</span>
558
559This example will compile and print `robot_name is: Some("Another name")`.
560Since `name` is a mutable reference, within the match arm code, we need to
561dereference using the `*` operator in order to be able to mutate the value.
562
563### Extra Conditionals with Match Guards
564
565You can introduce *match guards* as part of a match arm by specifying an
566additional `if` conditional after the pattern. The conditional can use
567variables created in the pattern. Listing 18-27 has a `match` expression with a
568match guard in the first arm:
569
570```rust
571let num = Some(4);
572
573match num {
574 Some(x) if x < 5 => println!("less than five: {}", x),
575 Some(x) => println!("{}", x),
576 None => (),
577}
578```
579
580<span class="caption">Listing 18-27: Adding a match guard to a pattern</span>
581
582This example will print `less than five: 4`. If `num` was instead `Some(7)`,
583this example would print `7`. Match guards allow you to express more complexity
584than patterns alone give you.
585
586In Listing 18-10, we saw that since patterns shadow variables, we weren't able
587to specify a pattern to express the case when a value was equal to a variable
588outside the `match`. Listing 18-28 shows how we can use a match guard to
589accomplish this:
590
591```rust
592fn main() {
593 let x = Some(5);
594 let y = 10;
595
596 match x {
597 Some(50) => println!("Got 50"),
598 Some(n) if n == y => println!("Matched, n = {:?}", n),
599 _ => println!("Default case, x = {:?}", x),
600 }
601
602 println!("at the end: x = {:?}, y = {:?}", x, y);
603}
604```
605
606<span class="caption">Listing 18-28: Using a match guard to test for equality
607with an outer variable</span>
608
609This will now print `Default case, x = Some(5)`. Because the second match arm
610is not introducing a new variable `y` that shadows the outer `y` in the
611pattern, we can use `y` in the match guard. We're still destructuring `x` to
612get the inner value `n`, and then we can compare `n` and `y` in the match guard.
613
614If you're using a match guard with multiple patterns specified by `|`, the
615match guard condition applies to all of the patterns. Listing 18-29 shows a
616match guard that applies to the value matched by all three patterns in the
617first arm:
618
619```rust
620let x = 4;
621let y = false;
622
623match x {
624 4 | 5 | 6 if y => println!("yes"),
625 _ => println!("no"),
626}
627```
628
629<span class="caption">Listing 18-29: Combining multiple patterns with a match
630guard</span>
631
632This prints `no` since the `if` condition applies to the whole pattern `4 | 5 |
6336`, not only to the last value `6`. In other words, the precedence of a match
634guard in relation to a pattern behaves like this:
635
636```text
637(4 | 5 | 6) if y => ...
638```
639
640rather than this:
641
642```text
6434 | 5 | (6 if y) => ...
644```
645
646### `@` Bindings
647
648In order to test a value in a pattern but also be able to create a variable
649bound to the value, we can use `@`. Listing 18-30 shows an example where we
650want to test that a `Message::Hello` `id` field is within the range `3...7` but
651also be able to bind to the value so that we can use it in the code associated
652with the arm:
653
654```rust
655enum Message {
656 Hello { id: i32 },
657}
658
659let msg = Message::Hello { id: 5 };
660
661match msg {
662 Message::Hello { id: id @ 3...7 } => {
663 println!("Found an id in range: {}", id)
664 },
665 Message::Hello { id: 10...12 } => {
666 println!("Found an id in another range")
667 },
668 Message::Hello { id } => {
669 println!("Found some other id: {}", id)
670 },
671}
672```
673
674<span class="caption">Listing 18-30: Using `@` to bind to a value in a pattern
675while also testing it</span>
676
677This example will print `Found an id in range: 5`. By specifying `id @` before
678the range, we're capturing whatever value matched the range while also testing
679it. In the second arm where we only have a range specified in the pattern, the
680code associated with the arm doesn't know if `id` is 10, 11, or 12, since we
681haven't saved the `id` value in a variable: we only know that the value matched
682something in that range if that arm's code is executed. In the last arm where
683we've specified a variable without a range, we do have the value available to
684use in the arm's code, but we haven't applied any other test to the value.
685Using `@` lets us test a value and save it in a variable within one pattern.
686
687## Summary
688
689Patterns are a useful feature of Rust that help to distinguish between
690different kinds of data. When used in `match` statements, Rust makes sure that
691your patterns cover every possible value. Patterns in `let` statements and
692function parameters make those constructs more powerful, enabling the
693destructuring of values into smaller parts at the same time as assigning to
694variables.
695
696Now, for the penultimate chapter of the book, let's take a look at some
697advanced parts of a variety of Rust's features.