Skip to content

Pattern Matching

match: exhaustive, checked by the compiler

Section titled “match: exhaustive, checked by the compiler”
fn area(
s: Shape,
): Double {
match s {
Circle(radius: r) => 3.14159 * r * r,
Rectangle(width: w, height: h) => w * h,
Triangle(base: b, height: h) => 0.5 * b * h,
}
}
match s {
Circle(r) => 3.14159 * r * r,
Rectangle(w, h) => w * h,
}

When the binding variable has the same name as the field, a trailing colon (field:) can be used instead of repeating the name (field: field):

// Long form
let Book(title: title, author: author, genre: genre) = b
// Shorthand. Equivalent
let Book(title:, author:, genre:) = b

Shorthand and explicit rename can be freely mixed:

let Book(title:, author: a, genre:) = b // title and genre use shorthand

The shorthand is valid in all pattern positions: let, let assert, match arms, and for loop heads.

Discarding unmentioned fields in variant patterns

Section titled “Discarding unmentioned fields in variant patterns”

A trailing .. inside a variant or record pattern means “I don’t care about the remaining fields”. Without it, you must bind every field the type declares.

match b {
Book(title:, ..) => debug title, // ignore author, genre, isbn, ...
}

.. is only valid at the end of the field list and binds nothing. If you want to capture something, use ...; if you want to discard, use ...

match score {
n if n >= 90 => "A",
n if n >= 80 => "B",
_ => "F",
}

Matches anything, binds nothing.

match weekday {
Sat => true,
Sun => true,
_ => false,
}
match status {
"active" => "go",
"paused" => "wait",
_ => "unknown",
}
let msg = match isAdmin, isActive {
true, true => "Active admin",
true, false => "Inactive admin",
false, _ => "User",
}

Multiple alternatives in a single arm. All alternatives must bind the same names with the same types.

match ticket {
VIP(price: p) | Bleachers(price: p) | GeneralAdmission(price: p) => p,
FreePass => 0,
}

Literal alternatives work too:

match status {
"active" | "pending" => true,
_ => false,
}

OR-patterns can have guards; the guard applies to the whole arm:

match ticket {
VIP(price: p) | Bleachers(price: p) if p > 50 => "premium",
_ => "standard",
}

OR-patterns are only valid as the top-level arm pattern in a single-subject match. They are not valid in let, let assert, for, or multi-subject match arms.

match items {
[] => "empty",
[head, ...rest] => "starts with ${head}",
[a, b, ..] => "at least two elements",
}

Rule of thumb: ... binds or spreads; .. discards. Three dots does something with the rest; two dots throws it away. The same rule applies to list patterns ([head, ...rest] vs [a, b, ..]) and to variant patterns (Book(title:, ..)) , ... has no form in variant patterns since variant fields are named, not positional.

let assert: runtime-checked single-pattern extraction

Section titled “let assert: runtime-checked single-pattern extraction”
let assert Ok(value: n) = someResult
let assert Circle(radius: r) = shape

Valid patterns in let assert: variant, tuple, identifier, wildcard. List patterns and literal patterns are not valid in let assert.