AnyCompiler

Enums and Pattern Matching

An enum defines a type as one of several named variants. Unlike many languages' enums, which are just labeled numbers, Rust's can be matched exhaustively, and each variant can even carry its own data.

enum Direction {
    Up,
    Down,
    Left,
    Right,
}

fn describe(dir: Direction) -> &'static str {
    match dir {
        Direction::Up => "going up",
        Direction::Down => "going down",
        Direction::Left => "going left",
        Direction::Right => "going right",
    }
}

fn main() {
    println!("{}", describe(Direction::Left));
}
Output
going left

match compares a value against each variant in turn, and the compiler checks that every possible variant is covered — leave one out, and it's a compile error, not a bug waiting to happen at runtime.

Enums that carry data

Each variant of an enum can hold its own data of its own shape — Shape::Circle carries a single f64, while Shape::Rectangle carries two. match destructures whichever variant is actually present, binding its data to a name you can use directly.

enum Shape {
    Circle(f64),
    Rectangle(f64, f64),
}

fn area(shape: Shape) -> f64 {
    match shape {
        Shape::Circle(radius) => 3.14159 * radius * radius,
        Shape::Rectangle(w, h) => w * h,
    }
}

fn main() {
    println!("{:.2}", area(Shape::Circle(2.0)));
    println!("{:.2}", area(Shape::Rectangle(3.0, 4.0)));
}
Output
12.57
12.00

Next: Option and Result — how Rust replaces null and exceptions with two ordinary enums.

Practice exercise

Define an enum Status with variants Active and Inactive. Write a function label(status: Status) -> &'static str that returns "online" for Active and "offline" for Inactive using match. Print label(Status::Active).