Enums and Pattern Matching

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.