Skip to content
8 changes: 4 additions & 4 deletions src/doc/trpl/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* [Concurrency](concurrency.md)
* [Error Handling](error-handling.md)
* [FFI](ffi.md)
* [Deref coercions](deref-coercions.md)
* [Syntax and Semantics](syntax-and-semantics.md)
* [Variable Bindings](variable-bindings.md)
* [Functions](functions.md)
Expand All @@ -30,15 +29,15 @@
* [Move semantics](move-semantics.md)
* [Enums](enums.md)
* [Match](match.md)
* [Patterns](patterns.md)
* [Structs](structs.md)
* [Patterns](patterns.md)
* [Method Syntax](method-syntax.md)
* [Drop](drop.md)
* [Vectors](vectors.md)
* [Strings](strings.md)
* [Generics](generics.md)
* [Traits](traits.md)
* [Operators and Overloading](operators-and-overloading.md)
* [Generics](generics.md)
* [Drop](drop.md)
* [if let](if-let.md)
* [Trait Objects](trait-objects.md)
* [Closures](closures.md)
Expand All @@ -53,6 +52,7 @@
* [Casting between types](casting-between-types.md)
* [Associated Types](associated-types.md)
* [Unsized Types](unsized-types.md)
* [Deref coercions](deref-coercions.md)
* [Macros](macros.md)
* [`unsafe` Code](unsafe-code.md)
* [Nightly Rust](nightly-rust.md)
Expand Down
129 changes: 25 additions & 104 deletions src/doc/trpl/enums.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,9 @@
% Enums

Finally, 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. These
can be used via their fully scoped names: `Character::Other` (more about `::`
below).
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.

```rust
enum Character {
Expand All @@ -14,14 +12,14 @@ enum Character {
}
```

Most normal types are allowed as the variant components of an `enum`. Here are
some examples:
Most types are allowed as the variant components of an `enum`. Here are some
examples:

```rust
struct Empty;
struct Color(i32, i32, i32);
struct Length(i32);
struct Status { Health: i32, Mana: i32, Attack: i32, Defense: i32 }
struct Stats { Health: i32, Mana: i32, Attack: i32, Defense: i32 }
struct HeightDatabase(Vec<i32>);
```

Expand All @@ -30,12 +28,12 @@ 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.

As with structures, 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:
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}
```rust,ignore
// These assignments both succeed
let ten = Character::Digit(10);
let four = Character::Digit(4);
Expand All @@ -50,98 +48,21 @@ let four_is_smaller = four <= ten;
let four_equals_ten = four == ten;
```

This 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
chapter. We don't know enough about Rust to implement equality yet, but we can
use the `Ordering` enum from the standard library, which does:
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:

```
enum Ordering {
Less,
Equal,
Greater,
}
```

Because `Ordering` has already been defined for us, we will import it with the
`use` keyword. Here's an example of how it is used:

```{rust}
use std::cmp::Ordering;

fn cmp(a: i32, b: i32) -> Ordering {
if a < b { Ordering::Less }
else if a > b { Ordering::Greater }
else { Ordering::Equal }
}

fn main() {
let x = 5;
let y = 10;

let ordering = cmp(x, y); // ordering: Ordering

if ordering == Ordering::Less {
println!("less");
} else if ordering == Ordering::Greater {
println!("greater");
} else if ordering == Ordering::Equal {
println!("equal");
}
}
```

The `::` symbol is used to indicate a namespace. In this case, `Ordering` lives
in the `cmp` submodule of the `std` module. We'll talk more about modules later
in the guide. For now, all you need to know is that you can `use` things from
the standard library if you need them.

Okay, let's talk about the actual code in the example. `cmp` is a function that
compares two things, and returns an `Ordering`. We return either
`Ordering::Less`, `Ordering::Greater`, or `Ordering::Equal`, depending on
whether the first value is less than, greater than, or equal to the second. Note
that each variant of the `enum` is namespaced under the `enum` itself: it's
`Ordering::Greater`, not `Greater`.

The `ordering` variable has the type `Ordering`, and so contains one of the
three values. We then do a bunch of `if`/`else` comparisons to check which
one it is.

This `Ordering::Greater` notation is too long. Let's use another form of `use`
to import the `enum` variants instead. This will avoid full scoping:

```{rust}
use std::cmp::Ordering::{self, Equal, Less, Greater};

fn cmp(a: i32, b: i32) -> Ordering {
if a < b { Less }
else if a > b { Greater }
else { Equal }
}

fn main() {
let x = 5;
let y = 10;

let ordering = cmp(x, y); // ordering: Ordering

if ordering == Less { println!("less"); }
else if ordering == Greater { println!("greater"); }
else if ordering == Equal { println!("equal"); }
}
```rust,ignore
Character::Digit(10);
Hand::Digit;
```

Importing variants is convenient and compact, but can also cause name conflicts,
so do this with caution. For this reason, it's normally considered better style
to `use` an enum rather than its variants directly.
Both variants are named `Digit`, but since they’re scoped to the `enum` name,

As you can see, `enum`s are quite a powerful tool for data representation, and
are even more useful when they're [generic][generics] across types. Before we
get to generics, though, let's talk about how to use enums with pattern
matching, a tool that will let us deconstruct sum types (the type theory term
for enums) like `Ordering` in a very elegant way that avoids all these messy
and brittle `if`/`else`s.
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.

[match]: ./match.html
[generics]: ./generics.html
[match]: match.html
[traits]: traits.html
Loading