Pattern Matching
match is how you take an enum apart. Each arm pairs a pattern with an expression, and the first matching arm runs.
Basic match
enum Status { case Active case Paused case Stopped }
let status = Status.Paused;
let label = match status {
.Active => "running",
.Paused => "halted",
.Stopped => "off"
};
match is an expression — it produces a value, so you can use it on the right of let.
Destructuring payloads
Bind payload fields by writing names in the pattern:
enum Shape {
case Circle(radius: Float64)
case Rectangle(width: Float64, height: Float64)
case Point
}
let shape = Shape.Rectangle(width: 3.0, height: 4.0);
let area = match shape {
.Circle(radius) => Float64.pi * radius * radius,
.Rectangle(width, height) => width * height,
.Point => 0.0
};
The names radius, width, height are new bindings introduced by the pattern. They're in scope only inside that arm.
Use _ to ignore a payload:
func use(value: Int) -> Int { value * 2 }
func fallback() -> Int { 0 }
let result: Result[Int, String] = .Ok(42);
let outcome = match result {
.Ok(value) => use(value),
.Err(_) => fallback()
};
Guards
A pattern can carry an if guard to refine a match further — n if n > 90 => "excellent". The first arm whose pattern and guard both succeed runs; if a pattern matches but the guard fails, control falls through to the next arm.
Known issue: on 0.16.0, guard arms in match hit a compiler bug at build time. Until the fix ships, express the same logic with range patterns (or an if/else chain):
let score = 85;
let grade = match score {
91..=100 => "excellent",
71..=90 => "good",
51..=70 => "passing",
_ => "needs work"
};
Nested patterns
Patterns can nest — destructure a payload that itself contains an enum:
enum Message {
case Urgent(text: String)
case Normal(text: String)
}
enum Envelope {
case Letter(Message)
case Empty
}
let envelope = Envelope.Letter(Message.Urgent(text: "server down"));
match envelope {
.Letter(.Urgent(message)) => { println("ALERT: \(message)"); },
.Letter(.Normal(message)) => { println(message); },
.Empty => {}
};
This is what makes nested enums ergonomic — you destructure as deep as you need in one place.
if let
When you only care about one variant, if let is shorter than a full match:
func lookup(id: Int) -> Optional[String] {
if id == 7 { .Some("Ada") } else { .None }
}
func greet(user: String) {
println("hello, \(user)");
}
if let .Some(user) = lookup(7) {
greet(user);
} else {
println("not found");
}
user is in scope inside the if block. The else is optional.
Exhaustiveness
The compiler verifies every variant is covered. Adding a new case to an enum will light up every existing match until you handle it. Treat that as a feature: it's how the compiler keeps your call sites honest as the data model evolves.