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.