Skip to content

Rust Enums

An enum (short for enumeration) defines a type that can be one of a fixed set of possibilities. If a struct is for “this thing has all of these fields,” an enum is for “this thing is exactly one of these options.”

enum Direction {
North,
South,
East,
West,
}
fn main() {
let heading = Direction::North;
match heading {
Direction::North => println!("Heading north"),
Direction::South => println!("Heading south"),
Direction::East => println!("Heading east"),
Direction::West => println!("Heading west"),
}
}

Output:

Heading north
▶ Try it Yourself

Notice match here doesn’t need a _ catch-all — because every possible Direction is listed, Rust can already tell the match is complete.

This is where Rust’s enums go further than a typical enum in other languages: each variant can carry its own data:

enum Shape {
Circle(f64), // radius
Rectangle(f64, f64), // width, height
}
fn area(shape: &Shape) -> f64 {
match shape {
Shape::Circle(radius) => 3.14159 * radius * radius,
Shape::Rectangle(width, height) => width * height,
}
}
fn main() {
let circle = Shape::Circle(3.0);
let rectangle = Shape::Rectangle(4.0, 5.0);
println!("{:.2}", area(&circle));
println!("{:.2}", area(&rectangle));
}

Output:

28.27
20.00
▶ Try it Yourself

Shape::Circle carries one f64 (the radius); Shape::Rectangle carries two. match pulls that data straight out for you in each arm — no separate step needed to “unwrap” it.

Option: an enum you’ve already been using

Section titled “Option: an enum you’ve already been using”

The Option type you’ll meet properly on its own page is just an enum defined in the standard library:

enum Option<T> {
Some(T),
None,
}

Once enums click, Option stops looking like special syntax — it’s a completely ordinary enum with two variants, one of which happens to carry a value.

Why not just use a struct with a “type” field?

Section titled “Why not just use a struct with a “type” field?”

You could imagine faking this with a struct and a string field like "circle" or "rectangle" — but then nothing stops you from typing "circl" by mistake, and you’d need to manually check which fields are actually relevant for each type. An enum makes invalid combinations impossible to write in the first place, and the compiler forces you to handle every variant.

  • An enum defines a type as one of several named variants: enum Direction { North, South, ... }.
  • Variants can carry their own data, and different variants can carry different data.
  • match naturally destructures enum data and requires every variant to be handled.
  • Option (and Result, covered next) are just enums from the standard library — nothing magic about them.