]> git.proxmox.com Git - rustc.git/blame - src/doc/book/src/ch06-02-match.md
New upstream version 1.44.1+dfsg1
[rustc.git] / src / doc / book / src / ch06-02-match.md
CommitLineData
13cf67c4
XL
1## The `match` Control Flow Operator
2
3Rust has an extremely powerful control flow operator called `match` that allows
4you 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
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 fact that the compiler confirms that all
9possible cases are handled.
10
11Think of a `match` expression as being 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 falls 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
69743fb6 20value in cents, as shown here in Listing 6-3.
13cf67c4
XL
21
22```rust
74b04a01 23{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-03/src/main.rs:here}}
13cf67c4
XL
24```
25
26<span class="caption">Listing 6-3: An enum and a `match` expression that has
27the variants of the enum as its patterns</span>
28
29Let’s break down the `match` in the `value_in_cents` function. First, we list
30the `match` keyword followed by an expression, which in this case is the value
31`coin`. This seems very similar to an expression used with `if`, but there’s a
32big difference: with `if`, the expression needs to return a Boolean value, but
33here, it can be any type. The type of `coin` in this example is the `Coin` enum
34that we defined on line 1.
35
36Next are the `match` arms. An arm has two parts: a pattern and some code. The
37first arm here has a pattern that is the value `Coin::Penny` and then the `=>`
38operator that separates the pattern and the code to run. The code in this case
39is just the value `1`. Each arm is separated from the next with a comma.
40
41When the `match` expression executes, it compares the resulting value against
42the pattern of each arm, in order. If a pattern matches the value, the code
43associated with that pattern is executed. If that pattern doesn’t match the
44value, execution continues to the next arm, much as in a coin-sorting machine.
45We can have as many arms as we need: in Listing 6-3, our `match` has four arms.
46
47The code associated with each arm is an expression, and the resulting value of
48the expression in the matching arm is the value that gets returned for the
49entire `match` expression.
50
51Curly brackets typically aren’t used if the match arm code is short, as it is
52in Listing 6-3 where each arm just returns a value. If you want to run multiple
53lines of code in a match arm, you can use curly brackets. For example, the
54following code would print “Lucky penny!” every time the method was called with
55a `Coin::Penny` but would still return the last value of the block, `1`:
56
57```rust
74b04a01 58{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-08-match-arm-multiple-lines/src/main.rs:here}}
13cf67c4
XL
59```
60
61### Patterns that Bind to Values
62
63Another useful feature of match arms is that they can bind to the parts of the
64values that match the pattern. This is how we can extract values out of enum
65variants.
66
67As an example, let’s change one of our enum variants to hold data inside it.
68From 1999 through 2008, the United States minted quarters with different
69designs for each of the 50 states on one side. No other coins got state
70designs, so only quarters have this extra value. We can add this information to
71our `enum` by changing the `Quarter` variant to include a `UsState` value stored
69743fb6 72inside it, which we’ve done here in Listing 6-4.
13cf67c4
XL
73
74```rust
74b04a01 75{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-04/src/main.rs:here}}
13cf67c4
XL
76```
77
78<span class="caption">Listing 6-4: A `Coin` enum in which the `Quarter` variant
79also holds a `UsState` value</span>
80
81Let’s imagine that a friend of ours is trying to collect all 50 state quarters.
82While we sort our loose change by coin type, we’ll also call out the name of
83the state associated with each quarter so if it’s one our friend doesn’t have,
84they can add it to their collection.
85
86In the match expression for this code, we add a variable called `state` to the
87pattern that matches values of the variant `Coin::Quarter`. When a
88`Coin::Quarter` matches, the `state` variable will bind to the value of that
89quarter’s state. Then we can use `state` in the code for that arm, like so:
90
91```rust
74b04a01 92{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-09-variable-in-pattern/src/main.rs:here}}
13cf67c4
XL
93```
94
95If we were to call `value_in_cents(Coin::Quarter(UsState::Alaska))`, `coin`
96would be `Coin::Quarter(UsState::Alaska)`. When we compare that value with each
97of the match arms, none of them match until we reach `Coin::Quarter(state)`. At
98that point, the binding for `state` will be the value `UsState::Alaska`. We can
99then use that binding in the `println!` expression, thus getting the inner
100state value out of the `Coin` enum variant for `Quarter`.
101
102### Matching with `Option<T>`
103
104In the previous section, we wanted to get the inner `T` value out of the `Some`
105case when using `Option<T>`; we can also handle `Option<T>` using `match` as we
106did with the `Coin` enum! Instead of comparing coins, we’ll compare the
107variants of `Option<T>`, but the way that the `match` expression works remains
108the same.
109
110Let’s say we want to write a function that takes an `Option<i32>` and, if
111there’s a value inside, adds 1 to that value. If there isn’t a value inside,
112the function should return the `None` value and not attempt to perform any
113operations.
114
115This function is very easy to write, thanks to `match`, and will look like
69743fb6 116Listing 6-5.
13cf67c4
XL
117
118```rust
74b04a01 119{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:here}}
13cf67c4
XL
120```
121
122<span class="caption">Listing 6-5: A function that uses a `match` expression on
123an `Option<i32>`</span>
124
125Let’s examine the first execution of `plus_one` in more detail. When we call
126`plus_one(five)`, the variable `x` in the body of `plus_one` will have the
127value `Some(5)`. We then compare that against each match arm.
128
129```rust,ignore
74b04a01 130{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:first_arm}}
13cf67c4
XL
131```
132
133The `Some(5)` value doesn’t match the pattern `None`, so we continue to the
134next arm.
135
136```rust,ignore
74b04a01 137{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:second_arm}}
13cf67c4
XL
138```
139
140Does `Some(5)` match `Some(i)`? Why yes it does! We have the same variant. The
141`i` binds to the value contained in `Some`, so `i` takes the value `5`. The
142code in the match arm is then executed, so we add 1 to the value of `i` and
143create a new `Some` value with our total `6` inside.
144
145Now let’s consider the second call of `plus_one` in Listing 6-5, where `x` is
146`None`. We enter the `match` and compare to the first arm.
147
148```rust,ignore
74b04a01 149{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:first_arm}}
13cf67c4
XL
150```
151
152It matches! There’s no value to add to, so the program stops and returns the
153`None` value on the right side of `=>`. Because the first arm matched, no other
154arms are compared.
155
156Combining `match` and enums is useful in many situations. You’ll see this
157pattern a lot in Rust code: `match` against an enum, bind a variable to the
158data inside, and then execute code based on it. It’s a bit tricky at first, but
159once you get used to it, you’ll wish you had it in all languages. It’s
160consistently a user favorite.
161
162### Matches Are Exhaustive
163
164There’s one other aspect of `match` we need to discuss. Consider this version
165of our `plus_one` function that has a bug and won’t compile:
166
167```rust,ignore,does_not_compile
74b04a01 168{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/src/main.rs:here}}
13cf67c4
XL
169```
170
171We didn’t handle the `None` case, so this code will cause a bug. Luckily, it’s
172a bug Rust knows how to catch. If we try to compile this code, we’ll get this
173error:
174
175```text
74b04a01 176{{#include ../listings/ch06-enums-and-pattern-matching/no-listing-10-non-exhaustive-match/output.txt}}
13cf67c4
XL
177```
178
179Rust knows that we didn’t cover every possible case and even knows which
180pattern we forgot! Matches in Rust are *exhaustive*: we must exhaust every last
181possibility in order for the code to be valid. Especially in the case of
182`Option<T>`, when Rust prevents us from forgetting to explicitly handle the
183`None` case, it protects us from assuming that we have a value when we might
ba9703b0 184have null, thus making the billion-dollar mistake discussed earlier impossible.
13cf67c4
XL
185
186### The `_` Placeholder
187
188Rust also has a pattern we can use when we don’t want to list all possible
189values. For example, a `u8` can have valid values of 0 through 255. If we only
190care about the values 1, 3, 5, and 7, we don’t want to have to list out 0, 2,
1914, 6, 8, 9 all the way up to 255. Fortunately, we don’t have to: we can use the
192special pattern `_` instead:
193
194```rust
74b04a01 195{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/no-listing-11-underscore-placeholder/src/main.rs:here}}
13cf67c4
XL
196```
197
198The `_` pattern will match any value. By putting it after our other arms, the
199`_` will match all the possible cases that aren’t specified before it. The `()`
200is just the unit value, so nothing will happen in the `_` case. As a result, we
201can say that we want to do nothing for all the possible values that we don’t
202list before the `_` placeholder.
203
204However, the `match` expression can be a bit wordy in a situation in which we
69743fb6 205care about only *one* of the cases. For this situation, Rust provides `if let`.
ba9703b0
XL
206
207More about patterns, and matching can be found in [chapter 18][ch18-00-patterns].
208
209[ch18-00-patterns]:
210ch18-00-patterns.html