]>
Commit | Line | Data |
---|---|---|
9346a6ac AL |
1 | % Enums |
2 | ||
bd371182 AL |
3 | An `enum` in Rust is a type that represents data that could be one of |
4 | several possible variants: | |
9346a6ac AL |
5 | |
6 | ```rust | |
bd371182 AL |
7 | enum Message { |
8 | Quit, | |
9 | ChangeColor(i32, i32, i32), | |
10 | Move { x: i32, y: i32 }, | |
11 | Write(String), | |
9346a6ac AL |
12 | } |
13 | ``` | |
14 | ||
bd371182 AL |
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. | |
9346a6ac | 23 | |
bd371182 AL |
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: | |
9346a6ac | 26 | |
bd371182 AL |
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, | |
9346a6ac AL |
36 | } |
37 | ||
bd371182 | 38 | let y: BoardGameTurn = BoardGameTurn::Move { squares: 1 }; |
9346a6ac AL |
39 | ``` |
40 | ||
bd371182 AL |
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. | |
9346a6ac | 43 | |
bd371182 AL |
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: | |
9346a6ac | 51 | |
bd371182 AL |
52 | ```rust,ignore |
53 | fn process_color_change(msg: Message) { | |
54 | let Message::ChangeColor(r, g, b) = msg; // compile-time error | |
9346a6ac AL |
55 | } |
56 | ``` | |
57 | ||
bd371182 AL |
58 | Not supporting these operations may seem rather limiting, but it’s a limitation |
59 | which we can overcome. There are two ways: by implementing equality ourselves, | |
60 | or by pattern matching variants with [`match`][match] expressions, which you’ll | |
61 | learn in the next section. We don’t know enough about Rust to implement | |
62 | equality yet, but we’ll find out in the [`traits`][traits] section. | |
9346a6ac | 63 | |
bd371182 AL |
64 | [match]: match.html |
65 | [if-let]: if-let.html | |
d9579d0f | 66 | [traits]: traits.html |
62682a34 SL |
67 | |
68 | # Constructors as functions | |
69 | ||
70 | An enum’s constructors can also be used like functions. For example: | |
71 | ||
72 | ```rust | |
73 | # enum Message { | |
74 | # Write(String), | |
75 | # } | |
76 | let m = Message::Write("Hello, world".to_string()); | |
77 | ``` | |
78 | ||
79 | Is the same as | |
80 | ||
81 | ```rust | |
82 | # enum Message { | |
83 | # Write(String), | |
84 | # } | |
85 | fn foo(x: String) -> Message { | |
86 | Message::Write(x) | |
87 | } | |
88 | ||
89 | let x = foo("Hello, world".to_string()); | |
90 | ``` | |
91 | ||
92 | This is not immediately useful to us, but when we get to | |
93 | [`closures`][closures], we’ll talk about passing functions as arguments to | |
94 | other functions. For example, with [`iterators`][iterators], we can do this | |
95 | to convert a vector of `String`s into a vector of `Message::Write`s: | |
96 | ||
97 | ```rust | |
98 | # enum Message { | |
99 | # Write(String), | |
100 | # } | |
101 | ||
102 | let v = vec!["Hello".to_string(), "World".to_string()]; | |
103 | ||
104 | let v1: Vec<Message> = v.into_iter().map(Message::Write).collect(); | |
105 | ``` | |
106 | ||
107 | [closures]: closures.html | |
108 | [iterators]: iterators.html |