Skip to content
You are reading v0.1, which is not the current release. Go to v0.4.

Patterns

Patterns appear in match and catch arms, local destructuring, for bindings, and other positions that bind or inspect a value.

_

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 behaviour, and costs something when they do not, because it is the one arm a newly added variant will silently fall into.

value

A bare identifier normally binds the matched value. A bare identifier that resolves to a nullary constructor is treated as that constructor rather than as a new binding.

0
3.14
"ready"
true
false

Integer, floating-point, string, and boolean literals can be used as literal patterns.

Option::None
Status::Ready

A qualified path selects the named constructor.

Option::Some(value)
Result::Err(error)
Message::Move(x, y)

The patterns inside parentheses correspond to the constructor’s payload positions.

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 :.

(left, right)
(x, y, z)

Tuple patterns may nest other patterns:

(Result::Ok(value), _)
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.

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 => Expr

The guard runs only after the pattern itself matches.

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.

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.

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.

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.1.0built frombd964738afb6on 2026-10-17 20:41ZVersioningSecurityContributingReleasesSource