]> git.proxmox.com Git - rustc.git/blame - src/doc/book/second-edition/nostarch/chapter06.md
New upstream version 1.23.0+dfsg1
[rustc.git] / src / doc / book / second-edition / nostarch / chapter06.md
CommitLineData
cc61c64b
XL
1
2[TOC]
3
4# Enums and Pattern Matching
5
6In this chapter we’ll look at *enumerations*, also referred to as *enums*.
7Enums allow you to define a type by enumerating its possible values. First,
8we’ll define and use an enum to show how an enum can encode meaning along with
9data. Next, we’ll explore a particularly useful enum, called `Option`, which
10expresses that a value can be either something or nothing. Then we’ll look at
11how pattern matching in the `match` expression makes it easy to run different
12code for different values of an enum. Finally, we’ll cover how the `if let`
13construct is another convenient and concise idiom available to you to handle
14enums in your code.
15
16Enums are a feature in many languages, but their capabilities differ in each
17language. Rust’s enums are most similar to *algebraic data types* in functional
18languages like F#, OCaml, and Haskell.
19
20## Defining an Enum
21
22Let’s look at a situation we might want to express in code and see why enums
23are useful and more appropriate than structs in this case. Say we need to work
24with IP addresses. Currently, two major standards are used for IP addresses:
25version four and version six. These are the only possibilities for an IP
26address that our program will come across: we can *enumerate* all possible
27values, which is where enumeration gets its name.
28
29Any IP address can be either a version four or a version six address but not
30both at the same time. That property of IP addresses makes the enum data
31structure appropriate for this case, because enum values can only be one of the
32variants. Both version four and version six addresses are still fundamentally
33IP addresses, so they should be treated as the same type when the code is
34handling situations that apply to any kind of IP address.
35
36We can express this concept in code by defining an `IpAddrKind` enumeration and
37listing the possible kinds an IP address can be, `V4` and `V6`. These are known
38as the *variants* of the enum:
39
abe05a73 40```
cc61c64b
XL
41enum IpAddrKind {
42 V4,
43 V6,
44}
45```
46
47`IpAddrKind` is now a custom data type that we can use elsewhere in our code.
48
49### Enum Values
50
51We can create instances of each of the two variants of `IpAddrKind` like this:
52
abe05a73 53```
cc61c64b
XL
54let four = IpAddrKind::V4;
55let six = IpAddrKind::V6;
56```
57
58Note that the variants of the enum are namespaced under its identifier, and we
59use a double colon to separate the two. The reason this is useful is that now
60both values `IpAddrKind::V4` and `IpAddrKind::V6` are of the same type:
61`IpAddrKind`. We can then, for instance, define a function that takes any
62`IpAddrKind`:
63
abe05a73 64```
cc61c64b
XL
65fn route(ip_type: IpAddrKind) { }
66```
67
68And we can call this function with either variant:
69
abe05a73 70```
cc61c64b
XL
71route(IpAddrKind::V4);
72route(IpAddrKind::V6);
73```
74
75Using enums has even more advantages. Thinking more about our IP address type,
76at the moment we don’t have a way to store the actual IP address *data*; we
77only know what *kind* it is. Given that you just learned about structs in
78Chapter 5, you might tackle this problem as shown in Listing 6-1:
79
abe05a73 80```
cc61c64b
XL
81enum IpAddrKind {
82 V4,
83 V6,
84}
85
86struct IpAddr {
87 kind: IpAddrKind,
88 address: String,
89}
90
91let home = IpAddr {
92 kind: IpAddrKind::V4,
93 address: String::from("127.0.0.1"),
94};
95
96let loopback = IpAddr {
97 kind: IpAddrKind::V6,
98 address: String::from("::1"),
99};
100```
101
cc61c64b
XL
102Listing 6-1: Storing the data and `IpAddrKind` variant of an IP address using a
103`struct`
cc61c64b
XL
104
105Here, we’ve defined a struct `IpAddr` that has two fields: a `kind` field that
106is of type `IpAddrKind` (the enum we defined previously) and an `address` field
107of type `String`. We have two instances of this struct. The first, `home`, has
108the value `IpAddrKind::V4` as its `kind` with associated address data of
109`127.0.0.1`. The second instance, `loopback`, has the other variant of
110`IpAddrKind` as its `kind` value, `V6`, and has address `::1` associated with
111it. We’ve used a struct to bundle the `kind` and `address` values together, so
112now the variant is associated with the value.
113
abe05a73
XL
114We can represent the same concept in a more concise way using just an enum,
115rather than an enum inside a struct, by putting data directly into each enum
cc61c64b
XL
116variant. This new definition of the `IpAddr` enum says that both `V4` and `V6`
117variants will have associated `String` values:
118
abe05a73 119```
cc61c64b
XL
120enum IpAddr {
121 V4(String),
122 V6(String),
123}
124
125let home = IpAddr::V4(String::from("127.0.0.1"));
126
127let loopback = IpAddr::V6(String::from("::1"));
128```
129
130We attach data to each variant of the enum directly, so there is no need for an
131extra struct.
132
133There’s another advantage to using an enum rather than a struct: each variant
134can have different types and amounts of associated data. Version four type IP
135addresses will always have four numeric components that will have values
136between 0 and 255. If we wanted to store `V4` addresses as four `u8` values but
137still express `V6` addresses as one `String` value, we wouldn’t be able to with
138a struct. Enums handle this case with ease:
139
abe05a73 140```
cc61c64b
XL
141enum IpAddr {
142 V4(u8, u8, u8, u8),
143 V6(String),
144}
145
146let home = IpAddr::V4(127, 0, 0, 1);
147
148let loopback = IpAddr::V6(String::from("::1"));
149```
150
151We’ve shown several different possibilities that we could define in our code
152for storing IP addresses of the two different varieties using an enum. However,
153as it turns out, wanting to store IP addresses and encode which kind they are
154is so common that the standard library has a definition we can use! Let’s look
155at how the standard library defines `IpAddr`: it has the exact enum and
156variants that we’ve defined and used, but it embeds the address data inside the
157variants in the form of two different structs, which are defined differently
158for each variant:
159
abe05a73 160```
cc61c64b
XL
161struct Ipv4Addr {
162 // details elided
163}
164
165struct Ipv6Addr {
166 // details elided
167}
168
169enum IpAddr {
170 V4(Ipv4Addr),
171 V6(Ipv6Addr),
172}
173```
174
175This code illustrates that you can put any kind of data inside an enum variant:
176strings, numeric types, or structs, for example. You can even include another
177enum! Also, standard library types are often not much more complicated than
178what you might come up with.
179
180Note that even though the standard library contains a definition for `IpAddr`,
181we can still create and use our own definition without conflict because we
182haven’t brought the standard library’s definition into our scope. We’ll talk
abe05a73 183more about bringing types into scope in Chapter 7.
cc61c64b
XL
184
185Let’s look at another example of an enum in Listing 6-2: this one has a wide
186variety of types embedded in its variants:
187
abe05a73 188```
cc61c64b
XL
189enum Message {
190 Quit,
191 Move { x: i32, y: i32 },
192 Write(String),
193 ChangeColor(i32, i32, i32),
194}
195```
196
cc61c64b
XL
197Listing 6-2: A `Message` enum whose variants each store different amounts and
198types of values
cc61c64b
XL
199
200This enum has four variants with different types:
201
202* `Quit` has no data associated with it at all.
203* `Move` includes an anonymous struct inside it.
204* `Write` includes a single `String`.
abe05a73 205* `ChangeColor` includes three `i32` values.
cc61c64b
XL
206
207Defining an enum with variants like the ones in Listing 6-2 is similar to
208defining different kinds of struct definitions except the enum doesn’t use the
209`struct` keyword and all the variants are grouped together under the `Message`
210type. The following structs could hold the same data that the preceding enum
211variants hold:
212
abe05a73 213```
cc61c64b
XL
214struct QuitMessage; // unit struct
215struct MoveMessage {
216 x: i32,
217 y: i32,
218}
219struct WriteMessage(String); // tuple struct
220struct ChangeColorMessage(i32, i32, i32); // tuple struct
221```
222
223But if we used the different structs, which each have their own type, we
224wouldn’t be able to as easily define a function that could take any of these
225kinds of messages as we could with the `Message` enum defined in Listing 6-2,
226which is a single type.
227
228There is one more similarity between enums and structs: just as we’re able to
229define methods on structs using `impl`, we’re also able to define methods on
230enums. Here’s a method named `call` that we could define on our `Message` enum:
231
abe05a73 232```
cc61c64b
XL
233impl Message {
234 fn call(&self) {
235 // method body would be defined here
236 }
237}
238
239let m = Message::Write(String::from("hello"));
240m.call();
241```
242
243The body of the method would use `self` to get the value that we called the
244method on. In this example, we’ve created a variable `m` that has the value
abe05a73
XL
245`Message::Write(String::from("hello"))`, and that is what `self` will be in the
246body of the `call` method when `m.call()` runs.
cc61c64b
XL
247
248Let’s look at another enum in the standard library that is very common and
249useful: `Option`.
250
251### The `Option` Enum and Its Advantages Over Null Values
252
253In the previous section, we looked at how the `IpAddr` enum let us use Rust’s
254type system to encode more information than just the data into our program.
255This section explores a case study of `Option`, which is another enum defined
256by the standard library. The `Option` type is used in many places because it
257encodes the very common scenario in which a value could be something or it
258could be nothing. Expressing this concept in terms of the type system means the
259compiler can check that you’ve handled all the cases you should be handling,
260which can prevent bugs that are extremely common in other programming languages.
261
262Programming language design is often thought of in terms of which features you
263include, but the features you exclude are important too. Rust doesn’t have the
264null feature that many other languages have. *Null* is a value that means there
265is no value there. In languages with null, variables can always be in one of
266two states: null or not-null.
267
268In “Null References: The Billion Dollar Mistake,” Tony Hoare, the inventor of
269null, has this to say:
270
271> I call it my billion-dollar mistake. At that time, I was designing the first
272> comprehensive type system for references in an object-oriented language. My
273> goal was to ensure that all use of references should be absolutely safe, with
3b2f2976 274> checking performed automatically by the compiler. But I couldn’t resist the
cc61c64b
XL
275> temptation to put in a null reference, simply because it was so easy to
276> implement. This has led to innumerable errors, vulnerabilities, and system
277> crashes, which have probably caused a billion dollars of pain and damage in
278> the last forty years.
279
280The problem with null values is that if you try to actually use a value that’s
281null as if it is a not-null value, you’ll get an error of some kind. Because
282this null or not-null property is pervasive, it’s extremely easy to make this
283kind of error.
284
285However, the concept that null is trying to express is still a useful one: a
286null is a value that is currently invalid or absent for some reason.
287
288The problem isn’t with the actual concept but with the particular
289implementation. As such, Rust does not have nulls, but it does have an enum
290that can encode the concept of a value being present or absent. This enum is
291`Option<T>`, and it is defined by the standard library as follows:
292
abe05a73 293```
cc61c64b
XL
294enum Option<T> {
295 Some(T),
296 None,
297}
298```
299
300The `Option<T>` enum is so useful that it’s even included in the prelude; you
abe05a73
XL
301don’t need to bring it into scope explicitly. In addition, so are its variants:
302you can use `Some` and `None` directly without prefixing them with `Option::`.
cc61c64b
XL
303`Option<T>` is still just a regular enum, and `Some(T)` and `None` are still
304variants of type `Option<T>`.
305
306The `<T>` syntax is a feature of Rust we haven’t talked about yet. It’s a
307generic type parameter, and we’ll cover generics in more detail in Chapter 10.
308For now, all you need to know is that `<T>` means the `Some` variant of the
309`Option` enum can hold one piece of data of any type. Here are some examples of
310using `Option` values to hold number types and string types:
311
abe05a73 312```
cc61c64b
XL
313let some_number = Some(5);
314let some_string = Some("a string");
315
316let absent_number: Option<i32> = None;
317```
318
319If we use `None` rather than `Some`, we need to tell Rust what type of
3b2f2976 320`Option<T>` we have, because the compiler can’t infer the type that the `Some`
cc61c64b
XL
321variant will hold by looking only at a `None` value.
322
323When we have a `Some` value, we know that a value is present, and the value is
324held within the `Some`. When we have a `None` value, in some sense, it means
325the same thing as null: we don’t have a valid value. So why is having
326`Option<T>` any better than having null?
327
328In short, because `Option<T>` and `T` (where `T` can be any type) are different
329types, the compiler won’t let us use an `Option<T>` value as if it was
330definitely a valid value. For example, this code won’t compile because it’s
abe05a73 331trying to add an `i8` to an `Option<i8>`:
cc61c64b 332
abe05a73 333```
cc61c64b
XL
334let x: i8 = 5;
335let y: Option<i8> = Some(5);
336
337let sum = x + y;
338```
339
340If we run this code, we get an error message like this:
341
abe05a73 342```
cc61c64b
XL
343error[E0277]: the trait bound `i8: std::ops::Add<std::option::Option<i8>>` is
344not satisfied
345 -->
346 |
abe05a73
XL
3475 | let sum = x + y;
348 | ^ no implementation for `i8 + std::option::Option<i8>`
cc61c64b
XL
349 |
350```
351
352Intense! In effect, this error message means that Rust doesn’t understand how
abe05a73 353to add an `i8` and an `Option<i8>`, because they’re different types. When we
cc61c64b
XL
354have a value of a type like `i8` in Rust, the compiler will ensure that we
355always have a valid value. We can proceed confidently without having to check
356for null before using that value. Only when we have an `Option<i8>` (or
357whatever type of value we’re working with) do we have to worry about possibly
358not having a value, and the compiler will make sure we handle that case before
359using the value.
360
361In other words, you have to convert an `Option<T>` to a `T` before you can
362perform `T` operations with it. Generally, this helps catch one of the most
363common issues with null: assuming that something isn’t null when it actually
364is.
365
366Not having to worry about missing an assumption of having a not-null value
367helps you to be more confident in your code. In order to have a value that can
368possibly be null, you must explicitly opt in by making the type of that value
369`Option<T>`. Then, when you use that value, you are required to explicitly
370handle the case when the value is null. Everywhere that a value has a type that
371isn’t an `Option<T>`, you *can* safely assume that the value isn’t null. This
372was a deliberate design decision for Rust to limit null’s pervasiveness and
373increase the safety of Rust code.
374
375So, how do you get the `T` value out of a `Some` variant when you have a value
376of type `Option<T>` so you can use that value? The `Option<T>` enum has a large
377number of methods that are useful in a variety of situations; you can check
378them out in its documentation. Becoming familiar with the methods on
379`Option<T>` will be extremely useful in your journey with Rust.
380
381In general, in order to use an `Option<T>` value, we want to have code that
382will handle each variant. We want some code that will run only when we have a
383`Some(T)` value, and this code is allowed to use the inner `T`. We want some
384other code to run if we have a `None` value, and that code doesn’t have a `T`
385value available. The `match` expression is a control flow construct that does
386just this when used with enums: it will run different code depending on which
387variant of the enum it has, and that code can use the data inside the matching
388value.
389
390## The `match` Control Flow Operator
391
392Rust has an extremely powerful control-flow operator called `match` that allows
393us to compare a value against a series of patterns and then execute code based
394on which pattern matches. Patterns can be made up of literal values, variable
abe05a73
XL
395names, wildcards, and many other things; Chapter 18 covers all the different
396kinds of patterns and what they do. The power of `match` comes from the
397expressiveness of the patterns and the compiler checks that make sure all
cc61c64b
XL
398possible cases are handled.
399
400Think of a `match` expression kind of like a coin sorting machine: coins slide
401down a track with variously sized holes along it, and each coin falls through
402the first hole it encounters that it fits into. In the same way, values go
403through each pattern in a `match`, and at the first pattern the value “fits,”
404the value will fall into the associated code block to be used during execution.
405
406Because we just mentioned coins, let’s use them as an example using `match`! We
407can write a function that can take an unknown United States coin and, in a
408similar way as the counting machine, determine which coin it is and return its
409value in cents, as shown here in Listing 6-3:
410
abe05a73 411```
cc61c64b
XL
412enum Coin {
413 Penny,
414 Nickel,
415 Dime,
416 Quarter,
417}
418
abe05a73 419fn value_in_cents(coin: Coin) -> u32 {
cc61c64b
XL
420 match coin {
421 Coin::Penny => 1,
422 Coin::Nickel => 5,
423 Coin::Dime => 10,
424 Coin::Quarter => 25,
425 }
426}
427```
428
cc61c64b
XL
429Listing 6-3: An enum and a `match` expression that has the variants of the enum
430as its patterns.
cc61c64b
XL
431
432Let’s break down the `match` in the `value_in_cents` function. First, we list
433the `match` keyword followed by an expression, which in this case is the value
434`coin`. This seems very similar to an expression used with `if`, but there’s a
435big difference: with `if`, the expression needs to return a boolean value.
436Here, it can be any type. The type of `coin` in this example is the `Coin` enum
437that we defined in Listing 6-3.
438
439Next are the `match` arms. An arm has two parts: a pattern and some code. The
440first arm here has a pattern that is the value `Coin::Penny` and then the `=>`
441operator that separates the pattern and the code to run. The code in this case
442is just the value `1`. Each arm is separated from the next with a comma.
443
444When the `match` expression executes, it compares the resulting value against
445the pattern of each arm, in order. If a pattern matches the value, the code
446associated with that pattern is executed. If that pattern doesn’t match the
447value, execution continues to the next arm, much like a coin sorting machine.
448We can have as many arms as we need: in Listing 6-3, our `match` has four arms.
449
450The code associated with each arm is an expression, and the resulting value of
451the expression in the matching arm is the value that gets returned for the
452entire `match` expression.
453
abe05a73
XL
454Curly brackets typically aren’t used if the match arm code is short, as it is
455in Listing 6-3 where each arm just returns a value. If you want to run multiple
456lines of code in a match arm, you can use curly brackets. For example, the
cc61c64b
XL
457following code would print out “Lucky penny!” every time the method was called
458with a `Coin::Penny` but would still return the last value of the block, `1`:
459
abe05a73
XL
460```
461fn value_in_cents(coin: Coin) -> u32 {
cc61c64b
XL
462 match coin {
463 Coin::Penny => {
464 println!("Lucky penny!");
465 1
466 },
467 Coin::Nickel => 5,
468 Coin::Dime => 10,
469 Coin::Quarter => 25,
470 }
471}
472```
473
474### Patterns that Bind to Values
475
476Another useful feature of match arms is that they can bind to parts of the
477values that match the pattern. This is how we can extract values out of enum
478variants.
479
480As an example, let’s change one of our enum variants to hold data inside it.
abe05a73 481From 1999 through 2008, the United States minted quarters with different
cc61c64b
XL
482designs for each of the 50 states on one side. No other coins got state
483designs, so only quarters have this extra value. We can add this information to
abe05a73 484our `enum` by changing the `Quarter` variant to include a `UsState` value stored
3b2f2976 485inside it, which we’ve done here in Listing 6-4:
cc61c64b 486
abe05a73 487```
cc61c64b
XL
488#[derive(Debug)] // So we can inspect the state in a minute
489enum UsState {
490 Alabama,
491 Alaska,
492 // ... etc
493}
494
495enum Coin {
496 Penny,
497 Nickel,
498 Dime,
499 Quarter(UsState),
500}
501```
502
cc61c64b
XL
503Listing 6-4: A `Coin` enum where the `Quarter` variant also holds a `UsState`
504value
cc61c64b
XL
505
506Let’s imagine that a friend of ours is trying to collect all 50 state quarters.
507While we sort our loose change by coin type, we’ll also call out the name of
508the state associated with each quarter so if it’s one our friend doesn’t have,
509they can add it to their collection.
510
511In the match expression for this code, we add a variable called `state` to the
512pattern that matches values of the variant `Coin::Quarter`. When a
513`Coin::Quarter` matches, the `state` variable will bind to the value of that
514quarter’s state. Then we can use `state` in the code for that arm, like so:
515
abe05a73
XL
516```
517fn value_in_cents(coin: Coin) -> u32 {
cc61c64b
XL
518 match coin {
519 Coin::Penny => 1,
520 Coin::Nickel => 5,
521 Coin::Dime => 10,
522 Coin::Quarter(state) => {
523 println!("State quarter from {:?}!", state);
524 25
525 },
526 }
527}
528```
529
530If we were to call `value_in_cents(Coin::Quarter(UsState::Alaska))`, `coin`
531would be `Coin::Quarter(UsState::Alaska)`. When we compare that value with each
532of the match arms, none of them match until we reach `Coin::Quarter(state)`. At
533that point, the binding for `state` will be the value `UsState::Alaska`. We can
534then use that binding in the `println!` expression, thus getting the inner
535state value out of the `Coin` enum variant for `Quarter`.
536
537### Matching with `Option<T>`
538
539In the previous section we wanted to get the inner `T` value out of the `Some`
540case when using `Option<T>`; we can also handle `Option<T>` using `match` as we
541did with the `Coin` enum! Instead of comparing coins, we’ll compare the
542variants of `Option<T>`, but the way that the `match` expression works remains
543the same.
544
545Let’s say we want to write a function that takes an `Option<i32>`, and if
546there’s a value inside, adds one to that value. If there isn’t a value inside,
547the function should return the `None` value and not attempt to perform any
548operations.
549
550This function is very easy to write, thanks to `match`, and will look like
551Listing 6-5:
552
abe05a73 553```
cc61c64b
XL
554fn plus_one(x: Option<i32>) -> Option<i32> {
555 match x {
556 None => None,
557 Some(i) => Some(i + 1),
558 }
559}
560
561let five = Some(5);
562let six = plus_one(five);
563let none = plus_one(None);
564```
565
cc61c64b 566Listing 6-5: A function that uses a `match` expression on an `Option<i32>`
cc61c64b
XL
567
568#### Matching `Some(T)`
569
570Let’s examine the first execution of `plus_one` in more detail. When we call
abe05a73 571`plus_one(five)`, the variable `x` in the body of `plus_one` will have the
cc61c64b
XL
572value `Some(5)`. We then compare that against each match arm.
573
abe05a73 574```
cc61c64b
XL
575None => None,
576```
577
abe05a73 578The `Some(5)` value doesn’t match the pattern `None`, so we continue to the
cc61c64b
XL
579next arm.
580
abe05a73 581```
cc61c64b
XL
582Some(i) => Some(i + 1),
583```
584
abe05a73 585Does `Some(5)` match `Some(i)`? Well yes it does! We have the same variant.
cc61c64b
XL
586The `i` binds to the value contained in `Some`, so `i` takes the value `5`. The
587code in the match arm is then executed, so we add one to the value of `i` and
588create a new `Some` value with our total `6` inside.
589
590#### Matching `None`
591
592Now let’s consider the second call of `plus_one` in Listing 6-5 where `x` is
abe05a73 593`None`. We enter the `match` and compare to the first arm.
cc61c64b 594
abe05a73 595```
cc61c64b
XL
596None => None,
597```
598
599It matches! There’s no value to add to, so the program stops and returns the
600`None` value on the right side of `=>`. Because the first arm matched, no other
601arms are compared.
602
603Combining `match` and enums is useful in many situations. You’ll see this
604pattern a lot in Rust code: `match` against an enum, bind a variable to the
605data inside, and then execute code based on it. It’s a bit tricky at first, but
606once you get used to it, you’ll wish you had it in all languages. It’s
607consistently a user favorite.
608
609### Matches Are Exhaustive
610
611There’s one other aspect of `match` we need to discuss. Consider this version
612of our `plus_one` function:
613
abe05a73 614```
cc61c64b
XL
615fn plus_one(x: Option<i32>) -> Option<i32> {
616 match x {
617 Some(i) => Some(i + 1),
618 }
619}
620```
621
622We didn’t handle the `None` case, so this code will cause a bug. Luckily, it’s
623a bug Rust knows how to catch. If we try to compile this code, we’ll get this
624error:
625
abe05a73 626```
cc61c64b
XL
627error[E0004]: non-exhaustive patterns: `None` not covered
628 -->
629 |
6306 | match x {
631 | ^ pattern `None` not covered
632```
633
634Rust knows that we didn’t cover every possible case and even knows which
635pattern we forgot! Matches in Rust are *exhaustive*: we must exhaust every last
636possibility in order for the code to be valid. Especially in the case of
637`Option<T>`, when Rust prevents us from forgetting to explicitly handle the
638`None` case, it protects us from assuming that we have a value when we might
639have null, thus making the billion dollar mistake discussed earlier.
640
641### The `_` Placeholder
642
643Rust also has a pattern we can use in situations when we don’t want to list all
644possible values. For example, a `u8` can have valid values of 0 through 255. If
645we only care about the values 1, 3, 5, and 7, we don’t want to have to list out
6460, 2, 4, 6, 8, 9 all the way up to 255. Fortunately, we don’t have to: we can
647use the special pattern `_` instead:
648
abe05a73 649```
cc61c64b
XL
650let some_u8_value = 0u8;
651match some_u8_value {
652 1 => println!("one"),
653 3 => println!("three"),
654 5 => println!("five"),
655 7 => println!("seven"),
656 _ => (),
657}
658```
659
660The `_` pattern will match any value. By putting it after our other arms, the
661`_` will match all the possible cases that aren’t specified before it. The `()`
662is just the unit value, so nothing will happen in the `_` case. As a result, we
663can say that we want to do nothing for all the possible values that we don’t
664list before the `_` placeholder.
665
666However, the `match` expression can be a bit wordy in a situation in which we
667only care about *one* of the cases. For this situation, Rust provides `if let`.
668
669## Concise Control Flow with `if let`
670
671The `if let` syntax lets you combine `if` and `let` into a less verbose way to
672handle values that match one pattern and ignore the rest. Consider the program
673in Listing 6-6 that matches on an `Option<u8>` value but only wants to execute
674code if the value is three:
675
abe05a73 676```
cc61c64b
XL
677let some_u8_value = Some(0u8);
678match some_u8_value {
679 Some(3) => println!("three"),
680 _ => (),
681}
682```
683
cc61c64b
XL
684Listing 6-6: A `match` that only cares about executing code when the value is
685`Some(3)`
cc61c64b
XL
686
687We want to do something with the `Some(3)` match but do nothing with any other
688`Some<u8>` value or the `None` value. To satisfy the `match` expression, we
689have to add `_ => ()` after processing just one variant, which is a lot of
690boilerplate code to add.
691
692Instead, we could write this in a shorter way using `if let`. The following
693code behaves the same as the `match` in Listing 6-6:
694
abe05a73 695```
cc61c64b
XL
696if let Some(3) = some_u8_value {
697 println!("three");
698}
699```
700
701`if let` takes a pattern and an expression separated by an `=`. It works the
702same way as a `match`, where the expression is given to the `match` and the
703pattern is its first arm.
704
705Using `if let` means you have less to type, less indentation, and less
706boilerplate code. However, we’ve lost the exhaustive checking that `match`
707enforces. Choosing between `match` and `if let` depends on what you’re doing in
708your particular situation and if gaining conciseness is an appropriate
709trade-off for losing exhaustive checking.
710
711In other words, you can think of `if let` as syntax sugar for a `match` that
712runs code when the value matches one pattern and then ignores all other values.
713
714We can include an `else` with an `if let`. The block of code that goes with the
715`else` is the same as the block of code that would go with the `_` case in the
716`match` expression that is equivalent to the `if let` and `else`. Recall the
717`Coin` enum definition in Listing 6-4, where the `Quarter` variant also held a
718`UsState` value. If we wanted to count all non-quarter coins we see while also
719announcing the state of the quarters, we could do that with a `match`
720expression like this:
721
abe05a73 722```
cc61c64b
XL
723let mut count = 0;
724match coin {
725 Coin::Quarter(state) => println!("State quarter from {:?}!", state),
726 _ => count += 1,
727}
728```
729
730Or we could use an `if let` and `else` expression like this:
731
abe05a73 732```
cc61c64b
XL
733let mut count = 0;
734if let Coin::Quarter(state) = coin {
735 println!("State quarter from {:?}!", state);
736} else {
737 count += 1;
738}
739```
740
741If you have a situation in which your program has logic that is too verbose to
742express using a `match`, remember that `if let` is in your Rust toolbox as well.
743
744## Summary
745
746We’ve now covered how to use enums to create custom types that can be one of a
747set of enumerated values. We’ve shown how the standard library’s `Option<T>`
748type helps you use the type system to prevent errors. When enum values have
749data inside them, you can use `match` or `if let` to extract and use those
750values, depending on how many cases you need to handle.
751
752Your Rust programs can now express concepts in your domain using structs and
753enums. Creating custom types to use in your API ensures type safety: the
754compiler will make certain your functions only get values of the type each
755function expects.
756
757In order to provide a well-organized API to your users that is straightforward
758to use and only exposes exactly what your users will need, let’s now turn to
759Rust’s modules.