RustArena

Step 1 of 7

Enums: one of a fixed set of variants

A struct says "a value has this and this and this". Lots of data is "this or that" instead: a traffic light is red, yellow or green; a direction is north, east, south or west; an order is pending, paid, shipped or delivered. For that, Rust has the enum (short for enumeration): a type that lists its possible variants. A value of the enum is always exactly one of them.

#[derive(Debug, PartialEq)]
enum Direction {
    North,
    East,
    South,
    West,
}

fn main() {
    let heading = Direction::East;
    println!("heading: {:?}", heading);
    println!("going north? {}", heading == Direction::North);
    let all = [Direction::North, Direction::East, Direction::South, Direction::West];
    println!("{:?}", all);
}
heading: East
going north? false
[North, East, South, West]

Why not a string or a number?

You could store a direction as "east" or as the number 1. But then nothing stops "Esat", "up", "" or 7: they all compile, and the bug shows up at run time (or never, silently doing the wrong thing). With an enum, a typo is a compile error:

#[derive(Debug, PartialEq)]
enum Direction {
    North,
    East,
}

fn main() {
    let d = Direction::Esat;
    println!("{}", d == Direction::North);
}
error[E0599]: no variant, associated function, or constant named `Esat` found for enum `Direction` in the current scope

This is your first taste of a big idea in Rust design: make invalid states unrepresentable. Choose types so that wrong values can't even be written down, and whole classes of bugs disappear before the program runs.

A first look at match

To do something different for each variant, use match. It compares a value with each pattern in turn and runs the code after => for the first one that fits:

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

fn arrow(d: Direction) -> char {
    match d {
        Direction::North => '^',
        Direction::East => '>',
        Direction::South => 'v',
        Direction::West => '<',
    }
}

fn main() {
    println!("{}{}{}{}", arrow(Direction::North), arrow(Direction::East), arrow(Direction::South), arrow(Direction::West));
}
^>v<

The match is the function's last expression, so its value (the arrow) is what arrow returns. The next step looks at match in depth.

Common mistakes

Your task

Fill in the blanks so the program prints total: 1050: the variant in the second arm, the arrow that separates a pattern from its value, and the enum's name when creating order.

Challenge 2

Write fn is_red(suit: Suit) -> bool using match: hearts and diamonds are red, clubs and spades are not.

Challenge 3

A SaaS product has three plans. Define an enum Plan with the variants Free, Pro and Team, and write fn monthly_cents(plan: Plan, seats: u32) -> u32:

Next: match: exhaustive by design