---
title: "11.1 Enums"
description: "An enum is a type whose value is exactly one of a fixed set of named variants; when an enum beats a bool, and why match pairs so naturally with enums."
url: "https://learnrust.net/chapter-11/enums/"
last_updated: "2026-06-13"
---

# 11.1 Enums

Chapter 10 built types whose parts coexist: a `Customer` has a name *and* an email *and* a balance, all at once. This chapter builds the other kind, where a value is exactly *one of* several alternatives, never more than one. That type is called an **enum**, and in Rust it's not the minor housekeeping feature it is in many languages. It's half of how you model data.

## The problem with using a bool

Suppose a program tracks a traffic light. Your first instinct might be a `bool`:

```rust
let is_green = true;
```

But a traffic light isn't a yes/no question. It's red, yellow, or green: three states, and a `bool` only has two. You could bolt on a second `bool` (`is_red`, `is_yellow`), but now nothing stops `is_red` and `is_green` from both being `true`, which is a state that can't physically exist. You've made an impossible situation *representable*, and somewhere down the line a bug will create it.

What you want is a type whose only possible values are the three real states. That's an enum:

```rust
enum TrafficLight {
    Red,
    Yellow,
    Green,
}
```

`TrafficLight` is now a type, like `Customer` was. Its values, the things after the brace, are called **variants**. A value of type `TrafficLight` is always exactly one of `Red`, `Yellow`, or `Green`, and the compiler guarantees there is no fourth option and no way to be two at once. The impossible state is now *unrepresentable*, which is the phrase lesson [3.6](https://learnrust.net/chapter-3/finding-issues-early/) promised this chapter would deliver on.

## Creating and using an enum value

Name a variant with the enum, a `::`, and the variant: `TrafficLight::Red`. The `::` is the same path separator you used for associated functions in lesson [10.6](https://learnrust.net/chapter-10/associated-functions-and-constructors/), and it reads the same way: "the `Red` that belongs to `TrafficLight`."

```rust
#[derive(Debug)]
enum TrafficLight {
    Red,
    Yellow,
    Green,
}

fn main() {
    let light = TrafficLight::Green;
    println!("{:?}", light);
}
```

```
Green
```

Enums take `#[derive(Debug)]` exactly like structs (lesson [10.7](https://learnrust.net/chapter-10/deriving-debug/)), and it prints the variant name. The variable `light` has type `TrafficLight`; the compiler infers it from the value, just as it inferred `i32` for `let x = 5;` back in lesson [4.9](https://learnrust.net/chapter-4/type-inference-and-annotations/). You could annotate it `let light: TrafficLight = ...` but you rarely need to.

## Enums pair with match

You've already met the tool for acting on an enum: `match`, from lesson [7.3](https://learnrust.net/chapter-7/introduction-to-match/). Back then `match` worked on integers and characters and you were promised it would come into its own later. This is later. Matching on an enum is the natural way to do something different for each variant:

```rust
fn action(light: &TrafficLight) -> &str {
    match light {
        TrafficLight::Red => "stop",
        TrafficLight::Yellow => "slow down",
        TrafficLight::Green => "go",
    }
}

fn main() {
    let light = TrafficLight::Green;
    println!("{}", action(&light));
}
```

```
go
```

Here's where the design pays off. Remember the **exhaustiveness** beat from lesson [7.3](https://learnrust.net/chapter-7/introduction-to-match/): a `match` must cover every possibility. With an enum, the compiler knows *exactly* what every possibility is, because you listed them. Delete the `Green` arm and the program is refused:

```
error[E0004]: non-exhaustive patterns: `TrafficLight::Green` not covered
 --> src/main.rs:8:11
  |
8 |     match light {
  |           ^^^^^ pattern `TrafficLight::Green` not covered
  |
note: `TrafficLight` defined here
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms
```

The compiler tells you precisely which variant you forgot. This is the feature that makes enums worth reaching for: when you later add a fourth variant, say `FlashingRed`, every `match` that doesn't handle it stops compiling, and the compiler hands you a checklist of every place in your program that needs updating. A `bool`-and-`if` version would just silently do the wrong thing. With an enum, "handle the new case everywhere" becomes a job the compiler assigns you, not one you have to remember.

> **Key insight**
>
> Reach for an enum whenever a value has a fixed, known set of states, especially if a `bool` (or two) is tempting but doesn't quite fit. The win isn't just readability. An enum plus `match` makes the compiler verify you've handled every case, and re-verify it every time the set of cases changes. "Make impossible states unrepresentable" is the slogan; exhaustiveness checking is the mechanism.

## C-style enums and underlying values

The enums above are sometimes called *C-style*: plain named variants with no extra data attached. By default each variant is just a distinct label, but you can also give them integer values, which is occasionally useful when an enum mirrors numbers from the outside world:

```rust
enum HttpStatus {
    Ok = 200,
    NotFound = 404,
    Teapot = 418,
}

fn main() {
    println!("{}", HttpStatus::NotFound as u32);
}
```

```
404
```

The `as u32` is the explicit cast from lesson [4.10](https://learnrust.net/chapter-4/numeric-conversions/): an enum variant can be turned into its integer value with `as`, but not automatically, and the reverse (number back to variant) isn't a cast at all, because an arbitrary number might not be a valid variant. You'll reach for this rarely. Most Rust enums never touch numbers, because the next lesson reveals what variants can carry instead, and it's far more interesting than integers.

## Quiz time

**Question #1**

Why is a `TrafficLight` enum a better model than two booleans `is_red` and `is_green`?

<details class="solution">
<summary>Show solution</summary>

The enum can only ever be exactly one of `Red`, `Yellow`, `Green`. Two booleans allow nonsensical combinations like `is_red = true, is_green = true` (both on) or both `false` (off), states a real light can't be in. The enum makes those impossible states unrepresentable, so they can't become bugs.

</details>

**Question #2**

This is refused. What's the error, and what is the compiler protecting you from?

```rust
enum Direction { North, South, East, West }

fn label(d: &Direction) -> &str {
    match d {
        Direction::North => "N",
        Direction::South => "S",
        Direction::East => "E",
    }
}
```

<details class="solution">
<summary>Show solution</summary>

E0004: non-exhaustive patterns, `Direction::West` not covered. The compiler knows `Direction` has exactly four variants and you handled three, so it refuses the incomplete `match`. It's protecting you from forgetting a case, and it would do the same the day you add a fifth direction. Add a `Direction::West => "W"` arm (or a `_` wildcard, though naming every variant is usually better, so a future variant forces you to revisit this code).

</details>

**Question #3**

Write an enum `Coin` with variants `Penny`, `Nickel`, `Dime`, `Quarter`, and a function `value_in_cents(coin: &Coin) -> u32` that returns 1, 5, 10, or 25 using `match`.

<details class="solution">
<summary>Show solution</summary>

```rust
enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

fn value_in_cents(coin: &Coin) -> u32 {
    match coin {
        Coin::Penny => 1,
        Coin::Nickel => 5,
        Coin::Dime => 10,
        Coin::Quarter => 25,
    }
}
```

All four variants are covered, so the `match` is exhaustive and compiles. This is the Rust Book's coin example; the next lesson upgrades it by letting a variant carry data.

</details>

These enums carry only their identity. The next lesson lets variants carry *values*, which is the feature that turns enums from a tidy list into one of Rust's most powerful ideas.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
