Store match bitor pattern as const

I want to store bitor pattern (e.g. 'a' | 'b' | 'c') as a constant so that I can reuse it in multiple match statements

if you code like this:

fn match_fn(a:u8)->bool{
    match a{
        b'a' | b'b'| b'c' => true,
        _ => false,
    }
}

then use a function to check them:

fn pattern(a:u8)->bool{
    a == b'a' || a == b'b' || a == b'c'
}

fn match_tgt(a:u8)->bool{
    match a {
        x if pattern(x) => true,
        _ => false,
    }
}

You’ll lose exhaustivity checking, though.

To the OP: patterns in Rust aren’t "first-class citizens", just syntax, so you can’t store them in variables or similar. But you can write a macro that expands to a pattern if necessary:

macro_rules! chars {
    () => { 'a' | 'b' }
}
5 Likes

Like we can store ranges, there should be a way to store patterns as well.

No, you actually can’t. As jdahlstrom said above, patterns are just syntax. They can’t be stored in variables. A stored value of type std::ops::Range/RangeInclusive/RangeFrom etc. is not the same thing as a range pattern. This code (Playground):

const RANGE: std::ops::Range<u8> = 0..10;

fn f(n: u8) {
    match n {
        RANGE => println!("within range"),
        _ => {},
    }
}

doesn’t do what you think. It gives this error:

error[E0308]: mismatched types
 --> src/lib.rs:5:9
  |
1 | const RANGE: std::ops::Range<u8> = 0..10;
  | -------------------------------- constant defined here
...
4 |     match n {
  |           - this expression has type `u8`
5 |         RANGE => println!("within range"),
  |         ^^^^^
  |         |
  |         expected `u8`, found `Range<u8>`
  |         `RANGE` is interpreted as a constant, not a new binding
  |
  = note: expected type `u8`
           found struct `std::ops::Range<u8>`
help: you may want to move the range into the match block
  |
5 |         0..10 => println!("within range"),
  |         ~~~~~

For more information about this error, try `rustc --explain E0308`.
error: could not compile `playground` (lib) due to 1 previous error

RANGE is not interpreted as a pattern in this case, but as a constant of type std::ops::Range<u8>[1]. rustc even suggests changing it to the correct code that matches 0 ≤ n < 10:

help: you may want to move the range into the match block
  |
5 |         0..10 => println!("within range"),
  |         ~~~~~

  1. RANGE is actually a pattern, but one that matches Range { start: 0, end: 10 } ↩︎

1 Like