about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/doc/trpl/SUMMARY.md3
-rw-r--r--src/doc/trpl/enums.md95
-rw-r--r--src/doc/trpl/match.md37
-rw-r--r--src/doc/trpl/structs.md79
-rw-r--r--src/doc/trpl/tuple-structs.md60
5 files changed, 162 insertions, 112 deletions
diff --git a/src/doc/trpl/SUMMARY.md b/src/doc/trpl/SUMMARY.md
index 68cca294398..03350de4af5 100644
--- a/src/doc/trpl/SUMMARY.md
+++ b/src/doc/trpl/SUMMARY.md
@@ -29,9 +29,9 @@
     * [References and Borrowing](references-and-borrowing.md)
     * [Lifetimes](lifetimes.md)
     * [Mutability](mutability.md)
+    * [Structs](structs.md)
     * [Enums](enums.md)
     * [Match](match.md)
-    * [Structs](structs.md)
     * [Patterns](patterns.md)
     * [Method Syntax](method-syntax.md)
     * [Vectors](vectors.md)
@@ -45,7 +45,6 @@
     * [Universal Function Call Syntax](ufcs.md)
     * [Crates and Modules](crates-and-modules.md)
     * [`const` and `static`](const-and-static.md)
-    * [Tuple Structs](tuple-structs.md)
     * [Attributes](attributes.md)
     * [`type` aliases](type-aliases.md)
     * [Casting between types](casting-between-types.md)
diff --git a/src/doc/trpl/enums.md b/src/doc/trpl/enums.md
index 80ea25eb35c..443f569a3e5 100644
--- a/src/doc/trpl/enums.md
+++ b/src/doc/trpl/enums.md
@@ -1,68 +1,63 @@
 % Enums
 
-Rust has a ‘sum type’, an `enum`. Enums are an incredibly useful feature of
-Rust, and are used throughout the standard library. An `enum` is a type which
-relates a set of alternates to a specific name. For example, below we define
-`Character` to be either a `Digit` or something else.
+An `enum` in Rust is a type that represents data that could be one of
+several possible variants:
 
 ```rust
-enum Character {
-    Digit(i32),
-    Other,
+enum Message {
+    Quit,
+    ChangeColor(i32, i32, i32),
+    Move { x: i32, y: i32 },
+    Write(String),
 }
 ```
 
-Most types are allowed as the variant components of an `enum`. Here are some
-examples:
+Each variant can optionally have data associated with it. The syntax for
+defining variants resembles the syntaxes used to define structs: you can
+have variants with no data (like unit-like structs), variants with named
+data, and variants with unnamed data (like tuple structs). Unlike
+separate struct definitions, however, an `enum` is a single type. A
+value of the enum can match any of the variants. For this reason, an
+enum is sometimes called a ‘sum type’: the set of possible values of the
+enum is the sum of the sets of possible values for each variant.
 
-```rust
-struct Empty;
-struct Color(i32, i32, i32);
-struct Length(i32);
-struct Stats { Health: i32, Mana: i32, Attack: i32, Defense: i32 }
-struct HeightDatabase(Vec<i32>);
-```
-
-You see that, depending on its type, an `enum` variant may or may not hold data.
-In `Character`, for instance, `Digit` gives a meaningful name for an `i32`
-value, where `Other` is only a name. However, the fact that they represent
-distinct categories of `Character` is a very useful property.
-
-The variants of an `enum` by default are not comparable with equality operators
-(`==`, `!=`), have no ordering (`<`, `>=`, etc.), and do not support other
-binary operations such as `*` and `+`. As such, the following code is invalid
-for the example `Character` type:
-
-```rust,ignore
-// These assignments both succeed
-let ten  = Character::Digit(10);
-let four = Character::Digit(4);
-
-// Error: `*` is not implemented for type `Character`
-let forty = ten * four;
+We use the `::` syntax to use the name of each variant: they’re scoped by the name
+of the `enum` itself. This allows both of these to work:
 
-// Error: `<=` is not implemented for type `Character`
-let four_is_smaller = four <= ten;
+```rust
+# enum Message {
+#     Move { x: i32, y: i32 },
+# }
+let x: Message = Message::Move { x: 3, y: 4 };
+
+enum BoardGameTurn {
+    Move { squares: i32 },
+    Pass,
+}
 
-// Error: `==` is not implemented for type `Character`
-let four_equals_ten = four == ten;
+let y: BoardGameTurn = BoardGameTurn::Move { squares: 1 };
 ```
 
-We use the `::` syntax to use the name of each variant: They’re scoped by the name
-of the `enum` itself. This allows both of these to work:
+Both variants are named `Move`, but since they’re scoped to the name of
+the enum, they can both be used without conflict.
+
+A value of an enum type contains information about which variant it is,
+in addition to any data associated with that variant. This is sometimes
+referred to as a ‘tagged union’, since the data includes a ‘tag’
+indicating what type it is. The compiler uses this information to
+enforce that you’re accessing the data in the enum safely. For instance,
+you can’t simply try to destructure a value as if it were one of the
+possible variants:
 
 ```rust,ignore
-Character::Digit(10);
-Hand::Digit;
+fn process_color_change(msg: Message) {
+    let Message::ChangeColor(r, g, b) = msg; // compile-time error
+}
 ```
 
-Both variants are named `Digit`, but since they’re scoped to the `enum` name,
-
-Not supporting these operations may seem rather limiting, but it’s a limitation
-which we can overcome. There are two ways: by implementing equality ourselves,
-or by pattern matching variants with [`match`][match] expressions, which you’ll
-learn in the next section. We don’t know enough about Rust to implement
-equality yet, but we’ll find out in the [`traits`][traits] section.
+We’ll see how to safely get data out of enums when we learn about the
+[`match`][match] and [`if let`][if-let] statements in the next few
+chapters.
 
 [match]: match.html
-[traits]: traits.html
+[if-let]: if-let.html
diff --git a/src/doc/trpl/match.md b/src/doc/trpl/match.md
index 86b94453389..2bb2359ba5a 100644
--- a/src/doc/trpl/match.md
+++ b/src/doc/trpl/match.md
@@ -61,3 +61,40 @@ let number = match x {
 ```
 
 Sometimes it’s a nice way of converting something from one type to another.
+
+# Matching on enums
+
+Another important use of the `match` keyword is to process the possible
+variants of an enum:
+
+```rust
+enum Message {
+    Quit,
+    ChangeColor(i32, i32, i32),
+    Move { x: i32, y: i32 },
+    Write(String),
+}
+
+fn quit() { /* ... */ }
+fn change_color(r: i32, g: i32, b: i32) { /* ... */ }
+fn move_cursor(x: i32, y: i32) { /* ... */ }
+
+fn process_message(msg: Message) {
+    match msg {
+        Message::Quit => quit(),
+        Message::ChangeColor(r, g, b) => change_color(r, g, b),
+        Message::Move { x: x, y: y } => move_cursor(x, y),
+        Message::Write(s) => println!("{}", s),
+    };
+}
+```
+
+Again, the Rust compiler checks exhaustiveness, so it demands that you
+have a match arm for every variant of the enum. If you leave one off, it
+will give you a compile-time error unless you use `_`.
+
+Unlike the previous uses of `match`, you can’t use the normal `if`
+statement to do this. You can use the [`if let`][if-let] statement,
+which can be seen as an abbreviated form of `match`.
+
+[if-let][if-let.html]
diff --git a/src/doc/trpl/structs.md b/src/doc/trpl/structs.md
index fcf928e427c..ad7ead93199 100644
--- a/src/doc/trpl/structs.md
+++ b/src/doc/trpl/structs.md
@@ -117,3 +117,82 @@ ones, and it will copy the values you don’t specify:
 let origin = Point3d { x: 0, y: 0, z: 0 };
 let point = Point3d { z: 1, x: 2, .. origin };
 ```
+
+# Tuple structs
+
+Rust has another data type that’s like a hybrid between a [tuple][tuple] and a
+struct, called a ‘tuple struct’. Tuple structs have a name, but
+their fields don’t:
+
+```rust
+struct Color(i32, i32, i32);
+struct Point(i32, i32, i32);
+```
+
+[tuple]: primitive-types.html#tuples
+
+These two will not be equal, even if they have the same values:
+
+```rust
+# struct Color(i32, i32, i32);
+# struct Point(i32, i32, i32);
+let black = Color(0, 0, 0);
+let origin = Point(0, 0, 0);
+```
+
+It is almost always better to use a struct than a tuple struct. We would write
+`Color` and `Point` like this instead:
+
+```rust
+struct Color {
+    red: i32,
+    blue: i32,
+    green: i32,
+}
+
+struct Point {
+    x: i32,
+    y: i32,
+    z: i32,
+}
+```
+
+Now, we have actual names, rather than positions. Good names are important,
+and with a struct, we have actual names.
+
+There _is_ one case when a tuple struct is very useful, though, and that’s a
+tuple struct with only one element. We call this the ‘newtype’ pattern, because
+it allows you to create a new type, distinct from that of its contained value
+and expressing its own semantic meaning:
+
+```rust
+struct Inches(i32);
+
+let length = Inches(10);
+
+let Inches(integer_length) = length;
+println!("length is {} inches", integer_length);
+```
+
+As you can see here, you can extract the inner integer type through a
+destructuring `let`, just as with regular tuples. In this case, the
+`let Inches(integer_length)` assigns `10` to `integer_length`.
+
+# Unit-like structs
+
+You can define a struct with no members at all:
+
+```rust
+struct Electron;
+```
+
+Such a struct is called ‘unit-like’ because it resembles the empty
+tuple, `()`, sometimes called ‘unit’. Like a tuple struct, it defines a
+new type.
+
+This is rarely useful on its own (although sometimes it can serve as a
+marker type), but in combination with other features, it can become
+useful. For instance, a library may ask you to create a structure that
+implements a certain [trait][trait] to handle events. If you don’t have
+any data you need to store in the structure, you can just create a
+unit-like struct.
diff --git a/src/doc/trpl/tuple-structs.md b/src/doc/trpl/tuple-structs.md
deleted file mode 100644
index bdaef70711a..00000000000
--- a/src/doc/trpl/tuple-structs.md
+++ /dev/null
@@ -1,60 +0,0 @@
-% Tuple Structs
-
-Rust has another data type that's like a hybrid between a [tuple][tuple] and a
-[struct][struct], called a ‘tuple struct’. Tuple structs have a name, but
-their fields don’t:
-
-```rust
-struct Color(i32, i32, i32);
-struct Point(i32, i32, i32);
-```
-
-[tuple]: primitive-types.html#tuples
-[struct]: structs.html
-
-These two will not be equal, even if they have the same values:
-
-```rust
-# struct Color(i32, i32, i32);
-# struct Point(i32, i32, i32);
-let black = Color(0, 0, 0);
-let origin = Point(0, 0, 0);
-```
-
-It is almost always better to use a struct than a tuple struct. We would write
-`Color` and `Point` like this instead:
-
-```rust
-struct Color {
-    red: i32,
-    blue: i32,
-    green: i32,
-}
-
-struct Point {
-    x: i32,
-    y: i32,
-    z: i32,
-}
-```
-
-Now, we have actual names, rather than positions. Good names are important,
-and with a struct, we have actual names.
-
-There _is_ one case when a tuple struct is very useful, though, and that’s a
-tuple struct with only one element. We call this the ‘newtype’ pattern, because
-it allows you to create a new type, distinct from that of its contained value
-and expressing its own semantic meaning:
-
-```rust
-struct Inches(i32);
-
-let length = Inches(10);
-
-let Inches(integer_length) = length;
-println!("length is {} inches", integer_length);
-```
-
-As you can see here, you can extract the inner integer type through a
-destructuring `let`, as we discussed previously in ‘tuples’. In this case, the
-`let Inches(integer_length)` assigns `10` to `integer_length`.