Enums and Pattern Matching
Nested Patterns
Rust patterns are composable: any place where a variable binding can appear inside a tuple, struct, enum variant, array, slice, or reference pattern can instead contain another pattern, allowing deeply nested data structures to be matched and destructured in a single step.
Composing Enums, Structs, Tuples, and Slices
Nested Pattern Hierarchy:
Event::HttpRequest {
method: Method::Post, <-- Nested unit enum variant
headers: [first_hdr, ..], <-- Nested slice pattern
body: Some(Payload::Json { bytes }), <-- Nested Option + struct-variant pattern
}
#[derive(Debug)]
enum Color {
Rgb(u8, u8, u8),
Hsv { h: u16, s: u8, v: u8 },
}
#[derive(Debug)]
enum Shape {
Circle { radius: u32, fill: Color },
Rectangle { width: u32, height: u32, fill: Color },
}
fn describe_shape(shape: &Shape) {
match shape {
// Match a Circle filled with pure black RGB(0, 0, 0):
Shape::Circle {
radius,
fill: Color::Rgb(0, 0, 0),
} => {
println!("Black circle of radius {radius}");
}
// Match any Circle filled with RGB and bind `r`, `g`, `b`:
Shape::Circle {
radius,
fill: Color::Rgb(r, g, b),
} => {
println!("Circle (r={radius}) with RGB({r}, {g}, {b})");
}
// Match a square (`width == height` via match guard) with HSV fill:
Shape::Rectangle {
width,
height,
fill: Color::Hsv { h, s, v },
} if width == height => {
println!("Square ({width}x{height}) with HSV({h}°, {s}%, {v}%)");
}
// Fallback for any other shape combination:
other => println!("Other shape: {other:?}"),
}
}
fn main() {
let s1 = Shape::Circle {
radius: 10,
fill: Color::Rgb(0, 0, 0),
};
let s2 = Shape::Circle {
radius: 25,
fill: Color::Rgb(255, 128, 0),
};
let s3 = Shape::Rectangle {
width: 50,
height: 50,
fill: Color::Hsv { h: 180, s: 80, v: 90 },
};
describe_shape(&s1);
describe_shape(&s2);
describe_shape(&s3);
}
Black circle of radius 10
Circle (r=25) with RGB(255, 128, 0)
Square (50x50) with HSV(180°, 80%, 90%)
Matching Nested Result<Option<T>, E> Values
Functions that read optional records from fallible I/O or databases often return Result<Option<T>, E>. Matching the nested structure directly handles every combination in one flat match block:
fn lookup_port(env_Result: Result<Option<u16>, &'static str>) -> u16 {
match env_Result {
Ok(Some(0)) => {
println!("Port 0 is reserved; falling back to 8080");
8080
}
Ok(Some(port)) => port,
Ok(None) => 8080, // Not configured; use default
Err(reason) => {
println!("Config error ({reason}); falling back to 8080");
8080
}
}
}
fn main() {
println!("Result 1: {}", lookup_port(Ok(Some(3000))));
println!("Result 2: {}", lookup_port(Ok(Some(0))));
println!("Result 3: {}", lookup_port(Ok(None)));
println!("Result 4: {}", lookup_port(Err("permission denied")));
}
Result 1: 3000
Port 0 is reserved; falling back to 8080
Result 2: 8080
Result 3: 8080
Config error (permission denied); falling back to 8080
Result 4: 8080