]> git.proxmox.com Git - rustc.git/blob - src/doc/book/src/ch06-02-match.md
New upstream version 1.63.0+dfsg1
[rustc.git] / src / doc / book / src / ch06-02-match.md
1 <a id="the-match-control-flow-operator"></a>
2 ## The `match` Control Flow Construct
3
4 Rust has an extremely powerful control flow construct called `match` that allows
5 you to compare a value against a series of patterns and then execute code based
6 on which pattern matches. Patterns can be made up of literal values, variable
7 names, wildcards, and many other things; Chapter 18 covers all the different
8 kinds of patterns and what they do. The power of `match` comes from the
9 expressiveness of the patterns and the fact that the compiler confirms that all
10 possible cases are handled.
11
12 Think of a `match` expression as being like a coin-sorting machine: coins slide
13 down a track with variously sized holes along it, and each coin falls through
14 the first hole it encounters that it fits into. In the same way, values go
15 through each pattern in a `match`, and at the first pattern the value “fits,”
16 the value falls into the associated code block to be used during execution.
17
18 Speaking of coins, let’s use them as an example using `match`! We can write a
19 function that takes an unknown United States coin and, in a similar way as the
20 counting machine, determines which coin it is and return its value in cents, as
21 shown here in Listing 6-3.
22
23 ```rust
24 {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-03/src/main.rs:here}}
25 ```
26
27 <span class="caption">Listing 6-3: An enum and a `match` expression that has
28 the variants of the enum as its patterns</span>
29
30 Let’s break down the `match` in the `value_in_cents` function. First, we list
31 the `match` keyword followed by an expression, which in this case is the value
32 `coin`. This seems very similar to an expression used with `if`, but there’s a
33 big difference: with `if`, the expression needs to return a Boolean value, but
34 here, it can return any type. The type of `coin` in this example is the `Coin`
35 enum that we defined on the first line.
36
37 Next are the `match` arms. An arm has two parts: a pattern and some code. The
38 first arm here has a pattern that is the value `Coin::Penny` and then the `=>`
39 operator that separates the pattern and the code to run. The code in this case
40 is just the value `1`. Each arm is separated from the next with a comma.
41
42 When the `match` expression executes, it compares the resulting value against
43 the pattern of each arm, in order. If a pattern matches the value, the code
44 associated with that pattern is executed. If that pattern doesn’t match the
45 value, execution continues to the next arm, much as in a coin-sorting machine.
46 We can have as many arms as we need: in Listing 6-3, our `match` has four arms.
47
48 The code associated with each arm is an expression, and the resulting value of
49 the expression in the matching arm is the value that gets returned for the
50 entire `match` expression.
51
52 We don’t typically use curly brackets if the match arm code is short, as it is
53 in Listing 6-3 where each arm just returns a value. If you want to run multiple
54 lines of code in a match arm, you must use curly brackets, and the comma
55 following the arm is then optional. For example, the following code prints
56 “Lucky penny!” every time the method is called with a `Coin::Penny`, but still
57 returns the last value of the block, `1`:
58
59 ```rust
60 {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-08-match-arm-multiple-lines/src/main.rs:here}}
61 ```
62
63 ### Patterns that Bind to Values
64
65 Another useful feature of match arms is that they can bind to the parts of the
66 values that match the pattern. This is how we can extract values out of enum
67 variants.
68
69 As an example, let’s change one of our enum variants to hold data inside it.
70 From 1999 through 2008, the United States minted quarters with different
71 designs for each of the 50 states on one side. No other coins got state
72 designs, so only quarters have this extra value. We can add this information to
73 our `enum` by changing the `Quarter` variant to include a `UsState` value stored
74 inside it, which we’ve done here in Listing 6-4.
75
76 ```rust
77 {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-04/src/main.rs:here}}
78 ```
79
80 <span class="caption">Listing 6-4: A `Coin` enum in which the `Quarter` variant
81 also holds a `UsState` value</span>
82
83 Let’s imagine that a friend is trying to collect all 50 state quarters. While
84 we sort our loose change by coin type, we’ll also call out the name of the
85 state associated with each quarter so if it’s one our friend doesn’t have, they
86 can add it to their collection.
87
88 In the match expression for this code, we add a variable called `state` to the
89 pattern that matches values of the variant `Coin::Quarter`. When a
90 `Coin::Quarter` matches, the `state` variable will bind to the value of that
91 quarter’s state. Then we can use `state` in the code for that arm, like so:
92
93 ```rust
94 {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-09-variable-in-pattern/src/main.rs:here}}
95 ```
96
97 If we were to call `value_in_cents(Coin::Quarter(UsState::Alaska))`, `coin`
98 would be `Coin::Quarter(UsState::Alaska)`. When we compare that value with each
99 of the match arms, none of them match until we reach `Coin::Quarter(state)`. At
100 that point, the binding for `state` will be the value `UsState::Alaska`. We can
101 then use that binding in the `println!` expression, thus getting the inner
102 state value out of the `Coin` enum variant for `Quarter`.
103
104 ### Matching with `Option<T>`
105
106 In the previous section, we wanted to get the inner `T` value out of the `Some`
107 case when using `Option<T>`; we can also handle `Option<T>` using `match` as we
108 did with the `Coin` enum! Instead of comparing coins, we’ll compare the
109 variants of `Option<T>`, but the way that the `match` expression works remains
110 the same.
111
112 Let’s say we want to write a function that takes an `Option<i32>` and, if
113 there’s a value inside, adds 1 to that value. If there isn’t a value inside,
114 the function should return the `None` value and not attempt to perform any
115 operations.
116
117 This function is very easy to write, thanks to `match`, and will look like
118 Listing 6-5.
119
120 ```rust
121 {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:here}}
122 ```
123
124 <span class="caption">Listing 6-5: A function that uses a `match` expression on
125 an `Option<i32>`</span>
126
127 Let’s examine the first execution of `plus_one` in more detail. When we call
128 `plus_one(five)`, the variable `x` in the body of `plus_one` will have the
129 value `Some(5)`. We then compare that against each match arm.
130
131 ```rust,ignore
132 {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:first_arm}}
133 ```
134
135 The `Some(5)` value doesn’t match the pattern `None`, so we continue to the
136 next arm.
137
138 ```rust,ignore
139 {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:second_arm}}
140 ```
141
142 Does `Some(5)` match `Some(i)`? Why yes it does! We have the same variant. The
143 `i` binds to the value contained in `Some`, so `i` takes the value `5`. The
144 code in the match arm is then executed, so we add 1 to the value of `i` and
145 create a new `Some` value with our total `6` inside.
146
147 Now let’s consider the second call of `plus_one` in Listing 6-5, where `x` is
148 `None`. We enter the `match` and compare to the first arm.
149
150 ```rust,ignore
151 {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:first_arm}}
152 ```
153
154 It matches! There’s no value to add to, so the program stops and returns the
155 `None` value on the right side of `=>`. Because the first arm matched, no other
156 arms are compared.
157
158 Combining `match` and enums is useful in many situations. You’ll see this
159 pattern a lot in Rust code: `match` against an enum, bind a variable to the
160 data inside, and then execute code based on it. It’s a bit tricky at first, but
161 once you get used to it, you’ll wish you had it in all languages. It’s
162 consistently a user favorite.
163
164 ### Matches Are Exhaustive
165
166 There’s one other aspect of `match` we need to discuss: the arms’ patterns must
167 cover all possibilities. Consider this version of our `plus_one` function,
168 which has a bug and won’t compile:
169
170 ```rust,ignore,does_not_compile
171 {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/src/main.rs:here}}
172 ```
173
174 We didn’t handle the `None` case, so this code will cause a bug. Luckily, it’s
175 a bug Rust knows how to catch. If we try to compile this code, we’ll get this
176 error:
177
178 ```console
179 {{#include ../listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/output.txt}}
180 ```
181
182 Rust knows that we didn’t cover every possible case and even knows which
183 pattern we forgot! Matches in Rust are *exhaustive*: we must exhaust every last
184 possibility in order for the code to be valid. Especially in the case of
185 `Option<T>`, when Rust prevents us from forgetting to explicitly handle the
186 `None` case, it protects us from assuming that we have a value when we might
187 have null, thus making the billion-dollar mistake discussed earlier impossible.
188
189 ### Catch-all Patterns and the `_` Placeholder
190
191 Using enums, we can also take special actions for a few particular values, but
192 for all other values take one default action. Imagine we’re implementing a game
193 where, if you roll a 3 on a dice roll, your player doesn’t move, but instead
194 gets a new fancy hat. If you roll a 7, your player loses a fancy hat. For all
195 other values, your player moves that number of spaces on the game board. Here’s
196 a `match` that implements that logic, with the result of the dice roll
197 hardcoded rather than a random value, and all other logic represented by
198 functions without bodies because actually implementing them is out of scope for
199 this example:
200
201 ```rust
202 {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-15-binding-catchall/src/main.rs:here}}
203 ```
204
205 For the first two arms, the patterns are the literal values 3 and 7. For the
206 last arm that covers every other possible value, the pattern is the variable
207 we’ve chosen to name `other`. The code that runs for the `other` arm uses the
208 variable by passing it to the `move_player` function.
209
210 This code compiles, even though we haven’t listed all the possible values a
211 `u8` can have, because the last pattern will match all values not specifically
212 listed. This catch-all pattern meets the requirement that `match` must be
213 exhaustive. Note that we have to put the catch-all arm last because the
214 patterns are evaluated in order. If we put the catch-all arm earlier, the other
215 arms would never run, so Rust will warn us if we add arms after a catch-all!
216
217 Rust also has a pattern we can use when we want a catch-all but don’t want to
218 *use* the value in the catch-all pattern: `_` is a special pattern that matches
219 any value and does not bind to that value. This tells Rust we aren’t going to
220 use the value, so Rust won’t warn us about an unused variable.
221
222 Let’s change the rules of the game: now, if you roll anything other than a 3 or
223 a 7, you must roll again. We no longer need to use the catch-all value, so we
224 can change our code to use `_` instead of the variable named `other`:
225
226 ```rust
227 {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-16-underscore-catchall/src/main.rs:here}}
228 ```
229
230 This example also meets the exhaustiveness requirement because we’re explicitly
231 ignoring all other values in the last arm; we haven’t forgotten anything.
232
233 Finally, we’ll change the rules of the game one more time, so that nothing else
234 happens on your turn if you roll anything other than a 3 or a 7. We can express
235 that by using the unit value (the empty tuple type we mentioned in [“The Tuple
236 Type”][tuples]<!-- ignore --> section) as the code that goes with the `_` arm:
237
238 ```rust
239 {{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-17-underscore-unit/src/main.rs:here}}
240 ```
241
242 Here, we’re telling Rust explicitly that we aren’t going to use any other value
243 that doesn’t match a pattern in an earlier arm, and we don’t want to run any
244 code in this case.
245
246 There’s more about patterns and matching that we’ll cover in [Chapter
247 18][ch18-00-patterns]<!-- ignore -->. For now, we’re going to move on to the
248 `if let` syntax, which can be useful in situations where the `match` expression
249 is a bit wordy.
250
251 [tuples]: ch03-02-data-types.html#the-tuple-type
252 [ch18-00-patterns]: ch18-00-patterns.html