Patterns
Patterns are used in match expressions, let bindings, and function parameters to destructure values.
Literal Patterns
match x {
0 => "zero",
1 => "one",
_ => "other",
}
Identifier Patterns
Bind the matched value to a name:
match value {
x => println!("Got: {}", x),
}
Wildcard Pattern
_ matches any value and discards it:
match pair {
(x, _) => println!("First: {}", x),
}
Enum Variant Patterns
Tuple Variants
match option {
Option::Some(value) => use_value(value),
Option::None => handle_empty(),
}
Named Field Variants
match shape {
Shape::Circle { radius } => 3.14159 * radius * radius,
Shape::Rectangle { width, height } => width * height,
Shape::Point => 0.0,
}
Nested Patterns
match result {
Result::Ok(Option::Some(value)) => use_value(value),
Result::Ok(Option::None) => handle_none(),
Result::Err(e) => handle_error(e),
}
Struct Patterns
let Point { x, y } = point;
In match:
match token {
Token { kind: TokenKind::Fn, span } => parse_function(span),
Token { kind: TokenKind::Struct, span } => parse_struct(span),
_ => parse_expression(),
}
Tuple Patterns
let (a, b) = (1, 2);
match pair {
(0, 0) => "origin",
(x, 0) => "x-axis",
(0, y) => "y-axis",
(x, y) => "other",
}
Reference Patterns
match &value {
&Some(x) => use_value(x),
&None => handle_none(),
}
Or Patterns
Match multiple alternatives in a single arm using |:
match x {
1 | 2 | 3 => "small",
4 | 5 | 6 => "medium",
_ => "large",
}
Or patterns work with enum variants:
match direction {
Direction::North | Direction::South => "vertical",
Direction::East | Direction::West => "horizontal",
}
They also work with nested patterns:
match result {
Result::Ok(1 | 2 | 3) => "small success",
Result::Ok(_) => "other success",
Result::Err(_) => "failure",
}
Range Patterns
Match a contiguous range of values using ..= (inclusive):
match score {
0..=59 => "F",
60..=69 => "D",
70..=79 => "C",
80..=89 => "B",
90..=100 => "A",
_ => "invalid",
}
Range patterns work with integer types:
match byte {
0x00..=0x1F => "control character",
0x20..=0x7E => "printable ASCII",
0x7F => "delete",
_ => "extended",
}
And with characters:
match c {
'a'..='z' => "lowercase",
'A'..='Z' => "uppercase",
'0'..='9' => "digit",
_ => "other",
}
Guard Clauses
Add a boolean condition to a match arm with if:
match value {
x if x > 100 => "large",
x if x > 0 => "positive",
x if x < 0 => "negative",
_ => "zero",
}
Guards can reference variables bound in the pattern:
match point {
Point { x, y } if x == y => "on diagonal",
Point { x, y } if x == 0 => "on y-axis",
Point { x, y } if y == 0 => "on x-axis",
_ => "general",
}
Guards combine with or patterns:
match value {
1 | 2 | 3 if verbose => {
println!("small value: {}", value);
"small"
}
_ => "other",
}
Guard Evaluation
- The guard expression is evaluated only if the structural pattern matches
- Guards do not affect exhaustiveness checking -- the compiler still requires all variants to be covered
- If the guard evaluates to
false, matching continues to the next arm
Exhaustiveness
The compiler verifies that match expressions cover all possible cases. Omitting a variant produces a compile-time error:
error: non-exhaustive match
--> program.joule:10:5
|
10 | match color {
| ^^^^^ missing variants: Blue
Use _ as a catch-all when you don't need to handle every variant explicitly.