Pattern matching
A pattern tests a value’s shape and names the parts inside it.
Match expressions
Section titled “Match expressions”match runs the first arm whose pattern fits the value, and evaluates to what that arm returns.
fn describe(n: int) -> string { match n { 0 => "zero", 1 => "one", _ => "many", }}Exhaustiveness
Section titled “Exhaustiveness”Patterns must cover all possible values:
enum Color { Red, Green, Blue }
match color { Color.Red => "red", Color.Green => "green",}The compiler enforces exhaustiveness:
✕ match is not exhaustive ╭─[example.lis:4:3] 3 │ fn name(color: Color) -> string { 4 │ match color { · ─────┬───── · ╰── not all patterns covered 5 │ Color.Red => "red", ╰──── help: Handle the missing case Color.Blue, e.g. Color.Blue => { ... } · code: [infer.non_exhaustive]Matchable patterns
Section titled “Matchable patterns”Literals
Section titled “Literals”Integer, boolean, string, and rune literals match exact values:
match status { "ok" => 200, "missing" => 404, _ => 500,}match letter { 'a' => "letter a", 'b' => "letter b", _ => "other",}Bindings
Section titled “Bindings”An identifier binds the matched value to a name:
match opt { Some(n) => n * 2,n is the value inside Some None => 0,}_ matches any value without binding:
match opt { Some(_) => "has value",_ discards the value inside Some None => "empty",}Tuples
Section titled “Tuples”Tuple patterns destructure by position:
let pair = (10, 20)
match pair { (0, 0) => "origin", (x, 0) => f"on x-axis at {x}", (0, y) => f"on y-axis at {y}", (x, y) => f"at ({x}, {y})",}Structs
Section titled “Structs”Struct patterns match fields by name:
struct Point { x: int, y: int,}
let point = Point { x: 10, y: 0 }
match point { Point { x: 0, y: 0 } => "origin", Point { x, y: 0 } => f"on x-axis at {x}", Point { x, y } => f"at ({x}, {y})",}Use .. to ignore remaining fields:
struct User { name: string, email: string, age: int,}
let user = User { name: "Alice", email: "alice@example.com", age: 30,}
match user { User { name: "", .. } => "hello, stranger", User { name, .. } => f"hello, {name}",.. ignores email and age}Enum variants
Section titled “Enum variants”Enum patterns match variants and destructure their payloads:
enum Message { Ready, Write(string), Move { x: int, y: int },}
let msg = Message.Write("hello")
match msg { Message.Ready => "ready", Message.Write(text) => f"writing: {text}", Message.Move { x, y } => f"moving to ({x}, {y})",}Inside a match arm, the enum qualifier can be omitted:
match msg { Ready => "ready",Message. qualifier omitted Write(text) => f"writing: {text}", Move { x, y } => f"moving to ({x}, {y})",}Slices and arrays
Section titled “Slices and arrays”Bracketed patterns match slice and array elements:
let items = [1, 2, 3]
match items { [] => "empty", [n] => f"single: {n}", [first, second] => f"pair: {first}, {second}", [first, ..rest] => f"first is {first}, {rest.length()} more",rest is [2, 3]}The rest pattern ..rest captures remaining elements as a Slice when matching a slice, or as an Array when matching an array. It must appear last. Elements after .. are not allowed.
Use .. without an identifier to ignore the rest:
match items { [first, ..] => first,.. discards all remaining elements [] => 0,}Alternative patterns
Section titled “Alternative patterns”Use | to match multiple patterns in one arm:
match direction { North | South => "north-south", East | West => "east-west",}Alternatives can bind variables if all of them bind the same names:
enum Event { KeyDown(rune), KeyUp(rune),}
match event { KeyDown(key) | KeyUp(key) => f"key: {key}",key is rune}as for value capture
Section titled “as for value capture”Use as to capture the entire matched value:
let mut history = Slice.new<Message>()
match msg { Ready => "ready", Write(text) => text, Move { x, .. } as moved => {moved is Move itself history = history.append(moved) f"moved to {x}" }}For an arm with alternatives, place as on each one:
match event { KeyDown(key) as pressed | KeyUp(key) as pressed => record(pressed, key),}Pattern guards
Section titled “Pattern guards”Add if after a pattern to require an additional condition:
match opt { Some(n) if n > 0 => "positive", Some(_) => "non-positive", None => "empty",}A guard can use a value captured with as:
match opt { Some(Point { x, .. }) as point if x > 0 => transform(point), _ => default,}Guards do not count toward exhaustiveness. If all arms have guards, a wildcard or catch-all arm is still required.
let else
Section titled “let else”A plain let needs a pattern that always matches. Some(n) might not, so use let else. The else branch runs when the match fails, and must return, break, or continue.
fn double_or_zero(opt: Option<int>) -> int { let Some(n) = opt else { return 0 } n * 2}A slice pattern that constrains the length can fail, because a slice has no fixed length:
fn first_two(items: Slice<int>) -> int { let [first, second, ..] = items else { return 0 } first + second}