matches! Macro
The matches! macro (matches!(expression, pattern [if guard])) tests whether an expression matches a pattern (and an optional if match guard) and returns a bool (true or false).
How matches! Expands
matches! is a standard library macro built directly on top of match:
matches!(expr, Pattern if guard)
// Expands to:
match expr {
Pattern if guard => true,
_ => false,
}
Checking Enum Variants Without Requiring PartialEq
Calling value == Enum::Variant requires the enum (and every type inside its variants) to implement PartialEq, and cannot ignore variant payloads with _. By contrast, matches! uses pattern matching, so it works on any type (even types that do not implement PartialEq) and can ignore payloads or test ranges:
enum JobState {
Queued,
Running { worker_id: u32 },
Failed { exit_code: i32, reason: String },
Completed,
}
fn main() {
let state = JobState::Failed {
exit_code: 137,
reason: String::from("OOM killed"),
};
// 1. Check variant regardless of payload:
let is_failed = matches!(state, JobState::Failed { .. });
// 2. Check multiple variants with `|`:
let is_terminal = matches!(state, JobState::Completed | JobState::Failed { .. });
// 3. Check variant payload with a match guard `if exit_code > 128`:
let killed_by_signal = matches!(
state,
JobState::Failed { exit_code, .. } if exit_code > 128
);
println!("is_failed: {is_failed}");
println!("is_terminal: {is_terminal}");
println!("killed_by_signal: {killed_by_signal}");
}
is_failed: true
is_terminal: true
killed_by_signal: true
Using matches! in Iterator Filters and Assertions
matches! is particularly concise inside .filter(...), .any(...), .all(...), and assert!(...):
fn main() {
let chars = ['a', '7', '_', 'Z', '!', '9'];
let identifier_chars: Vec<char> = chars
.into_iter()
.filter(|&c| matches!(c, 'a'..='z' | 'A'..='Z' | '0'..='9' | '_'))
.collect();
println!("Identifier characters: {identifier_chars:?}");
let response: Result<u16, &str> = Ok(200);
assert!(matches!(response, Ok(200..=299)));
}
Identifier characters: ['a', '7', '_', 'Z', '9']
Ownership Note: Borrowing in matches!
If your pattern inside matches!(val, Some(x) if ...) binds a non-Copy variable x by value and does not use if (or moves x), pass &val (matches!(&state, ...)) or use _ (matches!(state, Some(_))) so val is not moved.