|
1 | 1 | % Enums
|
2 | 2 |
|
3 |
| -Rust has a ‘sum type’, an `enum`. Enums are an incredibly useful feature of |
4 |
| -Rust, and are used throughout the standard library. An `enum` is a type which |
5 |
| -relates a set of alternates to a specific name. For example, below we define |
6 |
| -`Character` to be either a `Digit` or something else. |
| 3 | +An `enum` in Rust is a type that represents data that could be one of |
| 4 | +several possible variants: |
7 | 5 |
|
8 | 6 | ```rust
|
9 |
| -enum Character { |
10 |
| - Digit(i32), |
11 |
| - Other, |
| 7 | +enum Message { |
| 8 | + Quit, |
| 9 | + ChangeColor(i32, i32, i32), |
| 10 | + Move { x: i32, y: i32 }, |
| 11 | + Write(String), |
12 | 12 | }
|
13 | 13 | ```
|
14 | 14 |
|
15 |
| -Most types are allowed as the variant components of an `enum`. Here are some |
16 |
| -examples: |
| 15 | +Each variant can optionally have data associated with it. The syntax for |
| 16 | +defining variants resembles the syntaxes used to define structs: you can |
| 17 | +have variants with no data (like unit-like structs), variants with named |
| 18 | +data, and variants with unnamed data (like tuple structs). Unlike |
| 19 | +separate struct definitions, however, an `enum` is a single type. A |
| 20 | +value of the enum can match any of the variants. For this reason, an |
| 21 | +enum is sometimes called a ‘sum type’: the set of possible values of the |
| 22 | +enum is the sum of the sets of possible values for each variant. |
17 | 23 |
|
18 |
| -```rust |
19 |
| -struct Empty; |
20 |
| -struct Color(i32, i32, i32); |
21 |
| -struct Length(i32); |
22 |
| -struct Stats { Health: i32, Mana: i32, Attack: i32, Defense: i32 } |
23 |
| -struct HeightDatabase(Vec<i32>); |
24 |
| -``` |
25 |
| - |
26 |
| -You see that, depending on its type, an `enum` variant may or may not hold data. |
27 |
| -In `Character`, for instance, `Digit` gives a meaningful name for an `i32` |
28 |
| -value, where `Other` is only a name. However, the fact that they represent |
29 |
| -distinct categories of `Character` is a very useful property. |
30 |
| - |
31 |
| -The variants of an `enum` by default are not comparable with equality operators |
32 |
| -(`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not support other |
33 |
| -binary operations such as `*` and `+`. As such, the following code is invalid |
34 |
| -for the example `Character` type: |
35 |
| - |
36 |
| -```rust,ignore |
37 |
| -// These assignments both succeed |
38 |
| -let ten = Character::Digit(10); |
39 |
| -let four = Character::Digit(4); |
40 |
| -
|
41 |
| -// Error: `*` is not implemented for type `Character` |
42 |
| -let forty = ten * four; |
| 24 | +We use the `::` syntax to use the name of each variant: they’re scoped by the name |
| 25 | +of the `enum` itself. This allows both of these to work: |
43 | 26 |
|
44 |
| -// Error: `<=` is not implemented for type `Character` |
45 |
| -let four_is_smaller = four <= ten; |
| 27 | +```rust |
| 28 | +# enum Message { |
| 29 | +# Move { x: i32, y: i32 }, |
| 30 | +# } |
| 31 | +let x: Message = Message::Move { x: 3, y: 4 }; |
| 32 | + |
| 33 | +enum BoardGameTurn { |
| 34 | + Move { squares: i32 }, |
| 35 | + Pass, |
| 36 | +} |
46 | 37 |
|
47 |
| -// Error: `==` is not implemented for type `Character` |
48 |
| -let four_equals_ten = four == ten; |
| 38 | +let y: BoardGameTurn = BoardGameTurn::Move { squares: 1 }; |
49 | 39 | ```
|
50 | 40 |
|
51 |
| -We use the `::` syntax to use the name of each variant: They’re scoped by the name |
52 |
| -of the `enum` itself. This allows both of these to work: |
| 41 | +Both variants are named `Move`, but since they’re scoped to the name of |
| 42 | +the enum, they can both be used without conflict. |
| 43 | + |
| 44 | +A value of an enum type contains information about which variant it is, |
| 45 | +in addition to any data associated with that variant. This is sometimes |
| 46 | +referred to as a ‘tagged union’, since the data includes a ‘tag’ |
| 47 | +indicating what type it is. The compiler uses this information to |
| 48 | +enforce that you’re accessing the data in the enum safely. For instance, |
| 49 | +you can’t simply try to destructure a value as if it were one of the |
| 50 | +possible variants: |
53 | 51 |
|
54 | 52 | ```rust,ignore
|
55 |
| -Character::Digit(10); |
56 |
| -Hand::Digit; |
| 53 | +fn process_color_change(msg: Message) { |
| 54 | + let Message::ChangeColor(r, g, b) = msg; // compile-time error |
| 55 | +} |
57 | 56 | ```
|
58 | 57 |
|
59 |
| -Both variants are named `Digit`, but since they’re scoped to the `enum` name |
60 |
| -there's no ambiguity. |
61 |
| - |
62 |
| -Not supporting these operations may seem rather limiting, but it’s a limitation |
63 |
| -which we can overcome. There are two ways: by implementing equality ourselves, |
64 |
| -or by pattern matching variants with [`match`][match] expressions, which you’ll |
65 |
| -learn in the next section. We don’t know enough about Rust to implement |
66 |
| -equality yet, but we’ll find out in the [`traits`][traits] section. |
| 58 | +We’ll see how to safely get data out of enums when we learn about the |
| 59 | +[`match`][match] and [`if let`][if-let] statements in the next few |
| 60 | +chapters. |
67 | 61 |
|
68 | 62 | [match]: match.html
|
69 |
| -[traits]: traits.html |
| 63 | +[if-let]: if-let.html |
0 commit comments