Enums and Pattern Matching
Struct Variants
A struct variant is an enum variant that has named fields enclosed in curly braces VariantName { field1: T1, field2: T2 }, combining the multi-case sum-type nature of an enum with the self-documenting field names of a named-field struct.
Declaring and Constructing Struct Variants
#[derive(Debug)]
enum Shape {
Circle { radius: f64 },
Rectangle { width: f64, height: f64 },
Triangle { base: f64, height: f64 },
}
impl Shape {
fn area(&self) -> f64 {
match self {
Self::Circle { radius } => std::f64::consts::PI * radius * radius,
Self::Rectangle { width, height } => width * height,
Self::Triangle { base, height } => 0.5 * base * height,
}
}
}
fn main() {
let shapes = [
Shape::Circle { radius: 2.0 },
Shape::Rectangle { width: 4.0, height: 5.0 },
Shape::Triangle { base: 6.0, height: 3.0 },
];
for s in &shapes {
println!("{s:?} -> area = {:.2}", s.area());
}
}
Circle { radius: 2.0 } -> area = 12.57
Rectangle { width: 4.0, height: 5.0 } -> area = 20.00
Triangle { base: 6.0, height: 3.0 } -> area = 9.00
Field Init Shorthand and Pattern Matching on Struct Variants
Struct variants support the exact same field init shorthand at construction time and shorthand / renamed / .. rest patterns during pattern matching as regular named-field structs:
enum AuditLog {
Login { user: String, ip: String, success: bool },
}
fn summarize_log(entry: &AuditLog) {
match entry {
// Match `success: false`, bind `user`, and ignore `ip` with `..`:
AuditLog::Login { user, success: false, .. } => {
println!("ALERT: Failed login attempt for '{user}'");
}
// Rename `ip` to `source_ip` during destructuring:
AuditLog::Login { user, ip: source_ip, success: true } => {
println!("OK: '{user}' logged in from {source_ip}");
}
}
}
fn main() {
let user = String::from("admin");
let ip = String::from("10.0.0.1");
// Field init shorthand on a struct variant:
let ev1 = AuditLog::Login { user, ip, success: true };
let ev2 = AuditLog::Login {
user: String::from("guest"),
ip: String::from("192.168.1.9"),
success: false,
};
summarize_log(&ev1);
summarize_log(&ev2);
}
OK: 'admin' logged in from 10.0.0.1
ALERT: Failed login attempt for 'guest'
When to Use a Struct Variant vs Tuple Variant
| Use Case | Preferred Variant Style |
|---|---|
Single unambiguous value (Some(T), Text(String)) |
Tuple Variant |
2+ fields of the same type whose order could be confused (width vs height, src vs dst) |
Struct Variant |
| Variant payload needs its own methods or is passed to helper functions by itself | 1-element Tuple Variant wrapping a standalone struct (Resize(ResizeParams)) |