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