]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
1 | % Match |
2 | ||
bd371182 AL |
3 | Often, a simple [`if`][if]/`else` isn’t enough, because you have more than two |
4 | possible options. Also, conditions can get quite complex. Rust | |
5 | has a keyword, `match`, that allows you to replace complicated `if`/`else` | |
1a4d82fc JJ |
6 | groupings with something more powerful. Check it out: |
7 | ||
9346a6ac | 8 | ```rust |
1a4d82fc JJ |
9 | let x = 5; |
10 | ||
11 | match x { | |
12 | 1 => println!("one"), | |
13 | 2 => println!("two"), | |
14 | 3 => println!("three"), | |
15 | 4 => println!("four"), | |
16 | 5 => println!("five"), | |
17 | _ => println!("something else"), | |
18 | } | |
19 | ``` | |
20 | ||
bd371182 AL |
21 | [if]: if.html |
22 | ||
23 | `match` takes an expression and then branches based on its value. Each ‘arm’ of | |
9346a6ac AL |
24 | the branch is of the form `val => expression`. When the value matches, that arm’s |
25 | expression will be evaluated. It’s called `match` because of the term ‘pattern | |
26 | matching’, which `match` is an implementation of. There’s an [entire section on | |
bd371182 | 27 | patterns][patterns] that covers all the patterns that are possible here. |
1a4d82fc | 28 | |
9346a6ac AL |
29 | [patterns]: patterns.html |
30 | ||
bd371182 AL |
31 | So what’s the big advantage? Well, there are a few. First of all, `match` |
32 | enforces ‘exhaustiveness checking’. Do you see that last arm, the one with the | |
1a4d82fc JJ |
33 | underscore (`_`)? If we remove that arm, Rust will give us an error: |
34 | ||
35 | ```text | |
36 | error: non-exhaustive patterns: `_` not covered | |
37 | ``` | |
38 | ||
39 | In other words, Rust is trying to tell us we forgot a value. Because `x` is an | |
bd371182 AL |
40 | integer, Rust knows that it can have a number of different values – for |
41 | example, `6`. Without the `_`, however, there is no arm that could match, and | |
42 | so Rust refuses to compile the code. `_` acts like a ‘catch-all arm’. If none | |
43 | of the other arms match, the arm with `_` will, and since we have this | |
44 | catch-all arm, we now have an arm for every possible value of `x`, and so our | |
45 | program will compile successfully. | |
1a4d82fc | 46 | |
1a4d82fc | 47 | `match` is also an expression, which means we can use it on the right-hand |
9346a6ac | 48 | side of a `let` binding or directly where an expression is used: |
1a4d82fc | 49 | |
9346a6ac AL |
50 | ```rust |
51 | let x = 5; | |
1a4d82fc | 52 | |
bd371182 | 53 | let number = match x { |
9346a6ac AL |
54 | 1 => "one", |
55 | 2 => "two", | |
56 | 3 => "three", | |
57 | 4 => "four", | |
58 | 5 => "five", | |
59 | _ => "something else", | |
60 | }; | |
1a4d82fc JJ |
61 | ``` |
62 | ||
bd371182 AL |
63 | Sometimes it’s a nice way of converting something from one type to another. |
64 | ||
65 | # Matching on enums | |
66 | ||
67 | Another important use of the `match` keyword is to process the possible | |
68 | variants of an enum: | |
69 | ||
70 | ```rust | |
71 | enum Message { | |
72 | Quit, | |
73 | ChangeColor(i32, i32, i32), | |
74 | Move { x: i32, y: i32 }, | |
75 | Write(String), | |
76 | } | |
77 | ||
78 | fn quit() { /* ... */ } | |
79 | fn change_color(r: i32, g: i32, b: i32) { /* ... */ } | |
80 | fn move_cursor(x: i32, y: i32) { /* ... */ } | |
81 | ||
82 | fn process_message(msg: Message) { | |
83 | match msg { | |
84 | Message::Quit => quit(), | |
85 | Message::ChangeColor(r, g, b) => change_color(r, g, b), | |
86 | Message::Move { x: x, y: y } => move_cursor(x, y), | |
87 | Message::Write(s) => println!("{}", s), | |
88 | }; | |
89 | } | |
90 | ``` | |
91 | ||
92 | Again, the Rust compiler checks exhaustiveness, so it demands that you | |
93 | have a match arm for every variant of the enum. If you leave one off, it | |
94 | will give you a compile-time error unless you use `_`. | |
95 | ||
96 | Unlike the previous uses of `match`, you can’t use the normal `if` | |
97 | statement to do this. You can use the [`if let`][if-let] statement, | |
98 | which can be seen as an abbreviated form of `match`. | |
99 | ||
d9579d0f | 100 | [if-let]: if-let.html |