Skip to content

Commit 758d568

Browse files
committed
Merge branch 'trpl-fix-enums' of https://github.com/geofft/rust into rollup
2 parents 2c01eac + f59f41e commit 758d568

File tree

5 files changed

+162
-113
lines changed

5 files changed

+162
-113
lines changed

src/doc/trpl/SUMMARY.md

+1-2
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@
3131
* [References and Borrowing](references-and-borrowing.md)
3232
* [Lifetimes](lifetimes.md)
3333
* [Mutability](mutability.md)
34+
* [Structs](structs.md)
3435
* [Enums](enums.md)
3536
* [Match](match.md)
36-
* [Structs](structs.md)
3737
* [Patterns](patterns.md)
3838
* [Method Syntax](method-syntax.md)
3939
* [Vectors](vectors.md)
@@ -47,7 +47,6 @@
4747
* [Universal Function Call Syntax](ufcs.md)
4848
* [Crates and Modules](crates-and-modules.md)
4949
* [`const` and `static`](const-and-static.md)
50-
* [Tuple Structs](tuple-structs.md)
5150
* [Attributes](attributes.md)
5251
* [`type` aliases](type-aliases.md)
5352
* [Casting between types](casting-between-types.md)

src/doc/trpl/enums.md

+45-51
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,63 @@
11
% Enums
22

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:
75

86
```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),
1212
}
1313
```
1414

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.
1723

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:
4326

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+
}
4637

47-
// Error: `==` is not implemented for type `Character`
48-
let four_equals_ten = four == ten;
38+
let y: BoardGameTurn = BoardGameTurn::Move { squares: 1 };
4939
```
5040

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:
5351

5452
```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+
}
5756
```
5857

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.
6761

6862
[match]: match.html
69-
[traits]: traits.html
63+
[if-let]: if-let.html

src/doc/trpl/match.md

+37
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,40 @@ let number = match x {
6161
```
6262

6363
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+
100+
[if-let][if-let.html]

src/doc/trpl/structs.md

+79
Original file line numberDiff line numberDiff line change
@@ -117,3 +117,82 @@ ones, and it will copy the values you don’t specify:
117117
let origin = Point3d { x: 0, y: 0, z: 0 };
118118
let point = Point3d { z: 1, x: 2, .. origin };
119119
```
120+
121+
# Tuple structs
122+
123+
Rust has another data type that’s like a hybrid between a [tuple][tuple] and a
124+
struct, called a ‘tuple struct’. Tuple structs have a name, but
125+
their fields don’t:
126+
127+
```rust
128+
struct Color(i32, i32, i32);
129+
struct Point(i32, i32, i32);
130+
```
131+
132+
[tuple]: primitive-types.html#tuples
133+
134+
These two will not be equal, even if they have the same values:
135+
136+
```rust
137+
# struct Color(i32, i32, i32);
138+
# struct Point(i32, i32, i32);
139+
let black = Color(0, 0, 0);
140+
let origin = Point(0, 0, 0);
141+
```
142+
143+
It is almost always better to use a struct than a tuple struct. We would write
144+
`Color` and `Point` like this instead:
145+
146+
```rust
147+
struct Color {
148+
red: i32,
149+
blue: i32,
150+
green: i32,
151+
}
152+
153+
struct Point {
154+
x: i32,
155+
y: i32,
156+
z: i32,
157+
}
158+
```
159+
160+
Now, we have actual names, rather than positions. Good names are important,
161+
and with a struct, we have actual names.
162+
163+
There _is_ one case when a tuple struct is very useful, though, and that’s a
164+
tuple struct with only one element. We call this the ‘newtype’ pattern, because
165+
it allows you to create a new type, distinct from that of its contained value
166+
and expressing its own semantic meaning:
167+
168+
```rust
169+
struct Inches(i32);
170+
171+
let length = Inches(10);
172+
173+
let Inches(integer_length) = length;
174+
println!("length is {} inches", integer_length);
175+
```
176+
177+
As you can see here, you can extract the inner integer type through a
178+
destructuring `let`, just as with regular tuples. In this case, the
179+
`let Inches(integer_length)` assigns `10` to `integer_length`.
180+
181+
# Unit-like structs
182+
183+
You can define a struct with no members at all:
184+
185+
```rust
186+
struct Electron;
187+
```
188+
189+
Such a struct is called ‘unit-like’ because it resembles the empty
190+
tuple, `()`, sometimes called ‘unit’. Like a tuple struct, it defines a
191+
new type.
192+
193+
This is rarely useful on its own (although sometimes it can serve as a
194+
marker type), but in combination with other features, it can become
195+
useful. For instance, a library may ask you to create a structure that
196+
implements a certain [trait][trait] to handle events. If you don’t have
197+
any data you need to store in the structure, you can just create a
198+
unit-like struct.

src/doc/trpl/tuple-structs.md

-60
This file was deleted.

0 commit comments

Comments
 (0)