Reading — step 1 of 7
Learn
Enums in Rust are dramatically more powerful than in C-family languages. Each variant can carry its own data, making enums algebraic data types — perfect for modeling "this OR that OR the other." Chapter 6 of the Rust Book treats this as core language territory.
The basic form
enum Direction {
North,
South,
East,
West,
}
let d = Direction::North;
Like a C enum. Each variant is a value of the type.
Variants with data
This is where Rust enums shine:
enum Shape {
Circle(f64), // tuple-style — one f64
Rectangle { width: f64, height: f64 }, // struct-style — named fields
Triangle(f64, f64, f64), // three sides
Empty, // no data
}
let s1 = Shape::Circle(5.0);
let s2 = Shape::Rectangle { width: 3.0, height: 4.0 };
let s3 = Shape::Triangle(3.0, 4.0, 5.0);
let s4 = Shape::Empty;
Each variant is structurally distinct. The enum's value tells you both WHICH variant and its associated data.
Pattern matching with match
match deconstructs enum values, exhaustively:
fn area(s: &Shape) -> f64 {
match s {
Shape::Circle(r) => 3.14 * r * r,
Shape::Rectangle { width, height } => width * height,
Shape::Triangle(a, b, c) => {
let s = (a + b + c) / 2.0;
(s * (s - a) * (s - b) * (s - c)).sqrt()
}
Shape::Empty => 0.0,
}
}
The compiler enforces exhaustiveness. Add a new variant → every match block on Shape lights up at compile time. Free refactoring safety.
if let — single-pattern matching
When you only care about ONE variant:
if let Shape::Circle(r) = s {
println!("a circle with radius {}", r);
}
Cleaner than a match with one arm and a _ => {}.
while let — loop with a pattern
let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() {
println!("got {}", top);
}
Pops until the vector is empty (returns None).
Pattern matching extras
match n {
0 => println!("zero"),
1 | 2 | 3 => println!("small"), // multiple patterns
4..=10 => println!("medium"), // range
n if n > 100 => println!("big: {}", n), // guard
_ => println!("other"), // catch-all
}
Why ADTs matter
C's enums tell you "one of N integers." Rust's enums tell you "one of N possibilities, each with its own structured data." This collapses common patterns:
- Result types — Ok(value) or Err(error)
- Tree nodes — Leaf or Branch(left, right, value)
- Parser states — Token(string) or Symbol(int) or Punctuation(char)
- HTTP responses — Json(value) or Text(string) or Binary(bytes) or Empty
Building APIs around enums + match makes invalid states unrepresentable.
Common mistakes
- Forgetting catch-all
_ =>in non-exhaustive matches — compile error guides you. - Using
if letwhen match would express intent better — match is clearer for multi-variant cases. - Trying to use enum variants as type parameters — variants aren't types. The whole enum IS the type; variants are values.
- Unwrapping Option without checking —
.unwrap()panics on None; prefer pattern matching or?(next lesson).
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…