Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

First draft of enums #98

Merged
merged 1 commit into from May 13, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/SUMMARY.md
Expand Up @@ -26,7 +26,7 @@
- [Generics]()
- [Advanced]()

- [Enums]()
- [Enums](enums.md)
- [Match]()
- [Patterns]()
- [Option]()
Expand Down
148 changes: 148 additions & 0 deletions src/enums.md
@@ -0,0 +1,148 @@
# Enums

Next, let’s look at a feature of Rust that’s similar to structs, but also
different. Enumerations, or ‘enums’ as they’re more commonly referred to,
are an extremely powerful feature of Rust. Enums are a feature that are in many
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Feature word is too much repeated.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Enums are a feature that are in many" -> "Enums are a feature which is present in many"

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree with @GuillaumeGomez on the "Enums are a feature" sentence - it reads funny. I think the last two sentences of the paragraph can be combined in a way that reads smoother.

languages, but what they can do is different per-language. Rust’s enums are
most similar to enums in functional languages.

Here’s an example of an enum:

```rust
enum IpAddrKind {
V4,
V6,
}
```

This enum represents the kind of an IP address. There are two major standards
used for IP addresses: version four, and version six. Any IP address can be either
a version four address, or a version six address. But it cannot be both kinds at
the same time. This is where enums get their name: they allow us to enumerate all
of the possible kinds that our value can have.

We can create values of `IpAddrKind` like this:

```rust
# enum IpAddrKind {
# V4,
# V6,
# }

let four = IpAddrKind::V4;
let six = IpAddrKind::V6;
```

Note that the variants of the enum are namespaced under its name, and we use
the double colon to separate the two.

Enums have more tricks up their sleeves, however. Thinking more about our IP
address type, we don’t have a way to store the actual data of the IP address,
we only know what kind it is. Given that you just learned about structs, you
might tackle this problem like this:

```rust
enum IpAddrKind {
V4,
V6,
}

struct IpAddr {
kind: IpAddrKind,
address: String,
}

let home = IpAddr {
kind: IpAddrKind::V4,
address: String::from("127.0.0.1"),
};

let loopback = IpAddr {
kind: IpAddrKind::V6,
address: String::from("::1"),
};
```

We’ve used a struct to bundle the two values together: now we keep the kind
with the value itself. This design isn’t bad, exactly, but it wouldn’t be
considered idiomatic Rust. We can represent the same thing with just an enum:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It isn't idiomatic in any functional language I know as well. I'm wondering if specifying such a thing wouldn't be interesting? Well, in any case, I added the note.


```rust
enum IpAddr {
V4(String),
V6(String),
}

let home = IpAddr::V4(String::from("127.0.0.1"));

let loopback = IpAddr::V6(String::from("::1"));
```

We can attach data to each variant of the enum directly. No need for an extra
struct. But beyond that, this approach is better than using a struct alongside
our enum because we can attatch different kinds of data to each variant.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"attatch"

Imagine that instead of a `String`, we would prefer to store a `V4` as its four
individual components, while leaving the `V6` variant as a `String`. With our
struct, we’d be stuck. But enums deal with this case with ease:

```rust
enum IpAddr {
V4(u32, u32, u32, u32),
V6(String),
}

let home = IpAddr::V4(127, 0, 0, 1);

let loopback = IpAddr::V6(String::from("::1"));
```

You can put any kind of data inside of an enum variant, including another enum!
The `IpAddr` enum is [in the standard library][IpAddr], but it embeds two different
structs inside of its variants:

```rust
struct Ipv4Addr {
// details elided
}

struct Ipv6Addr {
// details elided
}

enum IpAddr {
V4(Ipv4Addr),
V6(Ipv6Addr),
}
```

[IpAddr]: http://doc.rust-lang.org/std/net/enum.IpAddr.html

Here’s an enum with a variety of types embedded in its variants:

```rust
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
```

* `Quit` has no data associated with it at all.
* `Move` includes an anonymous struct inside of it.
* `Write` includes a single `String`.
* `ChangeColor` includes three `i32`s.

We haven’t talked a lot about how to access the data inside an enum variant,
however. To do that, let’s move on to some new Rust syntax that’s especially
useful with enums: `match`.


Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a lot of blank lines. Is it normal?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I made a mistake 😄