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));
}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)));
}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).