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]
enum Direction { ... }defines a new type with four variants. Variants use UpperCamelCase, like type names.Direction::Eastcreates a value. The variants live inside the enum's name, so you writeDirection::in front.headinghas the typeDirection. A function can take aDirectionparameter, a struct can have aDirectionfield.#[derive(Debug, PartialEq)]works just like on structs:{:?}prints the variant's name, and==compares variants.
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
- Leaving out the enum's name:
let d = North;giveserror[E0425]: cannot find value `North` in this scope. WriteDirection::North. - A dot instead of
:::Direction.Northgiveserror[E0423]: cannot find value `Direction` in this scope.
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:
Freecosts 0,Procosts a flat 900, however many seats,Teamcosts 700 per seat.