]> git.proxmox.com Git - rustc.git/blame - src/doc/book/second-edition/src/ch06-02-match.md
New upstream version 1.23.0+dfsg1
[rustc.git] / src / doc / book / second-edition / src / ch06-02-match.md
CommitLineData
cc61c64b
XL
1## The `match` Control Flow Operator
2
3Rust has an extremely powerful control-flow operator called `match` that allows
4us to compare a value against a series of patterns and then execute code based
5on which pattern matches. Patterns can be made up of literal values, variable
abe05a73
XL
6names, wildcards, and many other things; Chapter 18 covers all the different
7kinds of patterns and what they do. The power of `match` comes from the
8expressiveness of the patterns and the compiler checks that make sure all
cc61c64b
XL
9possible cases are handled.
10
11Think of a `match` expression kind of like a coin sorting machine: coins slide
12down a track with variously sized holes along it, and each coin falls through
13the first hole it encounters that it fits into. In the same way, values go
14through each pattern in a `match`, and at the first pattern the value “fits,”
15the value will fall into the associated code block to be used during execution.
16
17Because we just mentioned coins, let’s use them as an example using `match`! We
18can write a function that can take an unknown United States coin and, in a
19similar way as the counting machine, determine which coin it is and return its
20value in cents, as shown here in Listing 6-3:
21
22```rust
23enum Coin {
24 Penny,
25 Nickel,
26 Dime,
27 Quarter,
28}
29
041b39d2 30fn value_in_cents(coin: Coin) -> u32 {
cc61c64b
XL
31 match coin {
32 Coin::Penny => 1,
33 Coin::Nickel => 5,
34 Coin::Dime => 10,
35 Coin::Quarter => 25,
36 }
37}
38```
39
40<span class="caption">Listing 6-3: An enum and a `match` expression that has
41the variants of the enum as its patterns.</span>
42
43Let’s break down the `match` in the `value_in_cents` function. First, we list
44the `match` keyword followed by an expression, which in this case is the value
45`coin`. This seems very similar to an expression used with `if`, but there’s a
46big difference: with `if`, the expression needs to return a boolean value.
47Here, it can be any type. The type of `coin` in this example is the `Coin` enum
48that we defined in Listing 6-3.
49
50Next are the `match` arms. An arm has two parts: a pattern and some code. The
51first arm here has a pattern that is the value `Coin::Penny` and then the `=>`
52operator that separates the pattern and the code to run. The code in this case
53is just the value `1`. Each arm is separated from the next with a comma.
54
55When the `match` expression executes, it compares the resulting value against
56the pattern of each arm, in order. If a pattern matches the value, the code
57associated with that pattern is executed. If that pattern doesn’t match the
58value, execution continues to the next arm, much like a coin sorting machine.
59We can have as many arms as we need: in Listing 6-3, our `match` has four arms.
60
61The code associated with each arm is an expression, and the resulting value of
62the expression in the matching arm is the value that gets returned for the
63entire `match` expression.
64
ea8adc8c
XL
65Curly brackets typically aren’t used if the match arm code is short, as it is
66in Listing 6-3 where each arm just returns a value. If you want to run multiple
67lines of code in a match arm, you can use curly brackets. For example, the
cc61c64b
XL
68following code would print out “Lucky penny!” every time the method was called
69with a `Coin::Penny` but would still return the last value of the block, `1`:
70
71```rust
72# enum Coin {
73# Penny,
74# Nickel,
75# Dime,
76# Quarter,
77# }
78#
041b39d2 79fn value_in_cents(coin: Coin) -> u32 {
cc61c64b
XL
80 match coin {
81 Coin::Penny => {
82 println!("Lucky penny!");
83 1
84 },
85 Coin::Nickel => 5,
86 Coin::Dime => 10,
87 Coin::Quarter => 25,
88 }
89}
90```
91
92### Patterns that Bind to Values
93
94Another useful feature of match arms is that they can bind to parts of the
95values that match the pattern. This is how we can extract values out of enum
96variants.
97
98As an example, let’s change one of our enum variants to hold data inside it.
7cac9316 99From 1999 through 2008, the United States minted quarters with different
cc61c64b
XL
100designs for each of the 50 states on one side. No other coins got state
101designs, so only quarters have this extra value. We can add this information to
ea8adc8c 102our `enum` by changing the `Quarter` variant to include a `UsState` value stored
3b2f2976 103inside it, which we’ve done here in Listing 6-4:
cc61c64b
XL
104
105```rust
106#[derive(Debug)] // So we can inspect the state in a minute
107enum UsState {
108 Alabama,
109 Alaska,
110 // ... etc
111}
112
113enum Coin {
114 Penny,
115 Nickel,
116 Dime,
117 Quarter(UsState),
118}
119```
120
121<span class="caption">Listing 6-4: A `Coin` enum where the `Quarter` variant
122also holds a `UsState` value</span>
123
124Let’s imagine that a friend of ours is trying to collect all 50 state quarters.
125While we sort our loose change by coin type, we’ll also call out the name of
126the state associated with each quarter so if it’s one our friend doesn’t have,
127they can add it to their collection.
128
129In the match expression for this code, we add a variable called `state` to the
130pattern that matches values of the variant `Coin::Quarter`. When a
131`Coin::Quarter` matches, the `state` variable will bind to the value of that
132quarter’s state. Then we can use `state` in the code for that arm, like so:
133
134```rust
135# #[derive(Debug)]
136# enum UsState {
137# Alabama,
138# Alaska,
139# }
140#
141# enum Coin {
142# Penny,
143# Nickel,
144# Dime,
145# Quarter(UsState),
146# }
147#
041b39d2 148fn value_in_cents(coin: Coin) -> u32 {
cc61c64b
XL
149 match coin {
150 Coin::Penny => 1,
151 Coin::Nickel => 5,
152 Coin::Dime => 10,
153 Coin::Quarter(state) => {
154 println!("State quarter from {:?}!", state);
155 25
156 },
157 }
158}
159```
160
161If we were to call `value_in_cents(Coin::Quarter(UsState::Alaska))`, `coin`
162would be `Coin::Quarter(UsState::Alaska)`. When we compare that value with each
163of the match arms, none of them match until we reach `Coin::Quarter(state)`. At
164that point, the binding for `state` will be the value `UsState::Alaska`. We can
165then use that binding in the `println!` expression, thus getting the inner
166state value out of the `Coin` enum variant for `Quarter`.
167
168### Matching with `Option<T>`
169
170In the previous section we wanted to get the inner `T` value out of the `Some`
171case when using `Option<T>`; we can also handle `Option<T>` using `match` as we
172did with the `Coin` enum! Instead of comparing coins, we’ll compare the
173variants of `Option<T>`, but the way that the `match` expression works remains
174the same.
175
176Let’s say we want to write a function that takes an `Option<i32>`, and if
177there’s a value inside, adds one to that value. If there isn’t a value inside,
178the function should return the `None` value and not attempt to perform any
179operations.
180
181This function is very easy to write, thanks to `match`, and will look like
182Listing 6-5:
183
184```rust
185fn plus_one(x: Option<i32>) -> Option<i32> {
186 match x {
187 None => None,
188 Some(i) => Some(i + 1),
189 }
190}
191
192let five = Some(5);
193let six = plus_one(five);
194let none = plus_one(None);
195```
196
197<span class="caption">Listing 6-5: A function that uses a `match` expression on
198an `Option<i32>`</span>
199
200#### Matching `Some(T)`
201
202Let’s examine the first execution of `plus_one` in more detail. When we call
203`plus_one(five)`, the variable `x` in the body of `plus_one` will have the
204value `Some(5)`. We then compare that against each match arm.
205
206```rust,ignore
207None => None,
208```
209
210The `Some(5)` value doesn’t match the pattern `None`, so we continue to the
211next arm.
212
213```rust,ignore
214Some(i) => Some(i + 1),
215```
216
3b2f2976 217Does `Some(5)` match `Some(i)`? Well yes it does! We have the same variant.
cc61c64b
XL
218The `i` binds to the value contained in `Some`, so `i` takes the value `5`. The
219code in the match arm is then executed, so we add one to the value of `i` and
220create a new `Some` value with our total `6` inside.
221
222#### Matching `None`
223
224Now let’s consider the second call of `plus_one` in Listing 6-5 where `x` is
225`None`. We enter the `match` and compare to the first arm.
226
227```rust,ignore
228None => None,
229```
230
231It matches! There’s no value to add to, so the program stops and returns the
232`None` value on the right side of `=>`. Because the first arm matched, no other
233arms are compared.
234
235Combining `match` and enums is useful in many situations. You’ll see this
236pattern a lot in Rust code: `match` against an enum, bind a variable to the
237data inside, and then execute code based on it. It’s a bit tricky at first, but
238once you get used to it, you’ll wish you had it in all languages. It’s
239consistently a user favorite.
240
241### Matches Are Exhaustive
242
243There’s one other aspect of `match` we need to discuss. Consider this version
244of our `plus_one` function:
245
246```rust,ignore
247fn plus_one(x: Option<i32>) -> Option<i32> {
248 match x {
249 Some(i) => Some(i + 1),
250 }
251}
252```
253
254We didn’t handle the `None` case, so this code will cause a bug. Luckily, it’s
255a bug Rust knows how to catch. If we try to compile this code, we’ll get this
256error:
257
258```text
259error[E0004]: non-exhaustive patterns: `None` not covered
260 -->
261 |
2626 | match x {
263 | ^ pattern `None` not covered
264```
265
266Rust knows that we didn’t cover every possible case and even knows which
267pattern we forgot! Matches in Rust are *exhaustive*: we must exhaust every last
268possibility in order for the code to be valid. Especially in the case of
269`Option<T>`, when Rust prevents us from forgetting to explicitly handle the
270`None` case, it protects us from assuming that we have a value when we might
271have null, thus making the billion dollar mistake discussed earlier.
272
273### The `_` Placeholder
274
275Rust also has a pattern we can use in situations when we don’t want to list all
276possible values. For example, a `u8` can have valid values of 0 through 255. If
277we only care about the values 1, 3, 5, and 7, we don’t want to have to list out
2780, 2, 4, 6, 8, 9 all the way up to 255. Fortunately, we don’t have to: we can
279use the special pattern `_` instead:
280
281```rust
282let some_u8_value = 0u8;
283match some_u8_value {
284 1 => println!("one"),
285 3 => println!("three"),
286 5 => println!("five"),
287 7 => println!("seven"),
288 _ => (),
289}
290```
291
292The `_` pattern will match any value. By putting it after our other arms, the
293`_` will match all the possible cases that aren’t specified before it. The `()`
294is just the unit value, so nothing will happen in the `_` case. As a result, we
295can say that we want to do nothing for all the possible values that we don’t
296list before the `_` placeholder.
297
298However, the `match` expression can be a bit wordy in a situation in which we
299only care about *one* of the cases. For this situation, Rust provides `if let`.