Patterns
Patterns appear in match and catch arms, local destructuring, for bindings, and other positions that bind or inspect a value.
Wildcard
Section titled “Wildcard”_The wildcard matches a value without binding it. Prefer an explicit arm per variant where the cases mean different things: a wildcard earns its place when the remaining cases genuinely share a behavior, and costs something when they do not, because it is the one arm a newly added variant will silently fall into.
Binding identifier
Section titled “Binding identifier”valueA bare identifier binds the matched value. value => .. matches anything and names it value.
A bare identifier that is the name of one of the value’s cases is an error. Over a Color, Red => .. would bind every color, not match Color::Red, so the compiler refuses it and names the pattern to write. This applies in every pattern (match, catch, let, for, and nested inside others) and to cases with a payload as well: NotFound => .. over an FsError is refused too. Write a constructor qualified (Color::Red, FsError::NotFound(path)), and bind with a name that is not a case.
The check is against the value’s type, not against what the file imports, so it applies to a value whose type the file never names. If a case is added to a type later, a binding that shares its name stops compiling. It does not silently start matching only that case.
A capitalized bare name is an error too, when it is no case of the
value’s type. A name in a pattern that starts with a capital letter must be a
case, so Gren => .. over a Color is refused, and the message offers the
nearest case, Color::Green, when one is within two edits (or a third of the
name’s length, if that is more). A const written as a pattern,
FAVORITE => .., would bind every value rather than compare against the
constant; compare with a guard instead:
match n { n if n == FAVORITE => "lucky", _ => "ordinary",}Bind with a lower-case name.
Literal patterns
Section titled “Literal patterns”03.14"ready"truefalseInteger, floating-point, string, and boolean literals can be used as literal patterns.
Nullary constructor path
Section titled “Nullary constructor path”Option::NoneStatus::ReadyA qualified path selects the named constructor.
Constructor payload pattern
Section titled “Constructor payload pattern”Option::Some(value)Result::Err(error)Message::Move(x, y)The patterns inside parentheses correspond to the constructor’s payload positions.
Record pattern
Section titled “Record pattern”Shorthand field binding:
User { id, name }Explicit nested pattern:
User { id: user_id, name: "admin",}General shape:
Path { field, field: Pattern, ...}A record pattern begins with a path and may bind fields by shorthand or supply another pattern after :.
Tuple pattern
Section titled “Tuple pattern”(left, right)(x, y, z)Tuple patterns may nest other patterns:
(Result::Ok(value), _)Patterns in match
Section titled “Patterns in match”match result { Result::Ok(value) => use_value(value), Result::Err(error) => handle(error),}The compiler checks exhaustiveness and unreachable arms. Adding a variant to a type therefore turns every exhaustive match on it into a compile error, which is the list of places that need a decision about the new case.
Match guards
Section titled “Match guards”A guard belongs to the arm after the pattern:
match score { value if value >= 90 => "high", value if value >= 50 => "medium", _ => "low",}General form:
Pattern if BoolExpr => ExprThe guard runs only after the pattern itself matches.
Patterns in let
Section titled “Patterns in let”let (left, right) = pair;let User { id, name } = user;A pattern used directly by let must be valid for the value’s type without requiring a missing-case branch. Refutable alternatives belong in match.
Patterns in for
Section titled “Patterns in for”for entry in Dict::entries(table) { print("${entry.key}: ${entry.value}");}The pattern binds each yielded item, under the same rules as let: valid for the item’s type, and irrefutable. Dict::entries yields a Pair, which is a record — a tuple pattern such as (key, value) is only valid where the item’s type is a tuple, and is refused otherwise.
for needs Step and Iterator in scope, and Pair too if the body reads the item’s fields: import std::core::{Dict, Iterator, Pair, Step, print};. See Control flow.
Patterns in catch
Section titled “Patterns in catch”load_user(id)! catch { UserError::NotFound(missing_id) => fallback(missing_id), UserError::Unavailable(reason) => offline(reason),}catch reuses the pattern syntax but adds failure-row semantics: exhaustively handling a failure type removes that type from the failures that can leave the expression.
Nesting
Section titled “Nesting”Patterns compose recursively:
match value { Envelope { payload: Result::Ok(User { id, name }), } => use_user(id, name), _ => fallback(),}Use nesting when it makes the shape clearer; split deeply nested business decisions into smaller matches when a single arm becomes difficult to read.
See Control flow for match result rules and Failures for catch semantics.
Khora 0.4.0built frombd964738afb6on 2026-10-17 20:41ZVersioningSecurityContributingReleasesSource