Match

From Rust Community Wiki
Jump to navigation Jump to search

See also: Reference – Match expressions

With the matchThis links to official Rust documentation keyword, a value is pattern matched against several match arms. Each match arm consists of at least one pattern and an optional if guard. Individual patterns are separated with a vertical bar (|).

Example[edit | edit source]

let x = Some(5);
match x {
    Some(1) | Some(3..=9) => println!("1st match arm"),
    Some(_) | None        => println!("2nd match arm"),
}

Patterns can introduce variable bindings, which can be used in the expression of the match arm. If a match arm has multiple patterns, all patterns must have the same bindings with the same types:

let x = Some(5);
match x {
    Some(n @ 1) | Some(n @ 3..=9) => println!("n is {}", n),
    Some(_) | None                => println!("2nd match arm"),
}

if guards[edit | edit source]

Each match arm can have an if guard with a condition that should be fulfilled:

let x = Some(5);
match x {
    // only match odd numbers:
    Some(n @ 1) | Some(n @ 3..=9) if n % 1 == 1 => {
        println!("1st match arm");
    }
    _ => println!("2nd match arm"),
}

Note that the if guard, if present, applies to all patterns in the same match arm. In the following example, the if guard is executed three times:

match () {
    _ | _ | _ if dbg!(false) => {}
    _ => {}
}

Rust processes match arms in consecutive order from top to bottom. It executes the first match arm where at least one pattern matches and the if guard, if present, returns true. It always executes at most one match arm.

Exhaustiveness[edit | edit source]

match blocks must be exhaustive: Every possible value of the matched type must be covered. For example, the following doesn't compile:

let x = Some(5);
match x {
    Some(5..=u32::MAX) => println!("1st match arm"),
    None               => println!("2nd match arm"),
}
error[E0004]: non-exhaustive patterns: `Some(0u32..=4u32)` not covered
   --> src/main.rs:3:11
    |
3   |     match x {
    |           ^ pattern `Some(0u32..=4u32)` not covered
    |

The reason why match blocks must be exhaustive, is that they are expressions and can return a value:

let x = Some(5);
let _: i32 = match x {
    Some(x) => x * 2,
    None    => 42,
};

Trailing commas[edit | edit source]

The right side of a match arm, after the =>, must be an expression. The match arms are separated with commas (,). The comma after the last match arm is optional. The comma is also optional if the expression is a block expression, which includes:

  • regular blocks ({})
  • unsafe blocks (unsafe {})
  • loops (loop {}, while .. {}, while let .. = .. {}, for .. in .. {})
  • conditions (if .. {}, if let .. = .. {}, etc.)
  • match blocks (match .. {})
  • async blocks (async {}, async move {})
  • try blocks (try {}, these are still experimental)

Example[edit | edit source]

let x = Some(5);
match x {
    Some(x) => loop {
        break;
    } // no comma needed
    _ => {} // no comma needed
}

How many match arms are executed?[edit | edit source]

Usually, exactly one match arm in a match expression is executed, but there are two exceptions:

  1. When matching on an enum with no variants or on the never type, there are no match arms, and the code is never executed:
    #![feature(never_type)]
    
    fn never(x: !) -> ! {
        match x {}
    }
    
  2. When an if guard panics or diverges, no match arm is executed:
    fn panics() -> ! {
        match 42 {
            _ if panic!() => unreachable!(),
            _             => unreachable!(),
        }
    }