8

In Rust, matching a value like this works:

let x = 1;

match x {
    1 => println!("one"),
    2 => println!("two"),
    _ => println!("something else")
}

But using values from a vector instead of hard-coded numbers in match doesn't work:

let x = 1;
let list = vec![1, 2];

match x {
    list[0] => println!("one"),
    list[1] => println!("two"),
    _ => println!("something else")
}

This fails with the message:

error: expected one of `=>`, `@`, `if`, or `|`, found `[`
 --> src/main.rs:6:9
  |
6 |     list[0] => println!("one"),
  |         ^ expected one of `=>`, `@`, `if`, or `|` here

Why doesn't it work?

  • See also: [Why can I compare a String to a &str using if, but not when using match?](https://stackoverflow.com/questions/49886160/why-can-i-compare-a-string-to-a-str-using-if-but-not-when-using-match/49889545#49889545) – Peter Hall Jan 15 '19 at 14:53
  • That not the purpose of matching. – Stargateur Jan 15 '19 at 16:32

1 Answers1

17

The pattern of a match arm is defined as

Syntax
Pattern :
     LiteralPattern
   | IdentifierPattern
   | WildcardPattern
   | RangePattern
   | ReferencePattern
   | StructPattern
   | TupleStructPattern
   | TuplePattern
   | GroupedPattern
   | SlicePattern
   | PathPattern
   | MacroInvocation

It's either constant (including literal) or structural, not computed. A value defined as list[0] matches none of those definitions.

Fortunately, a match arm may also contain a guard expression, which allows for this:

let x = 1;
let list = vec![1, 2];

match x {
    _ if x == list[0] => println!("one"),
    _ if x == list[1] => println!("two"),
    _ => println!("something else")
}

Using if else would be cleaner, though (or a different structure if you have more cases, like a map, or the index).

Denys Séguret
  • 372,613
  • 87
  • 782
  • 758
  • Going to the grammar is nice, however I think we could go slightly higher level: a pattern is first and foremost **structural**. Apart from the exception of literal patterns, a pattern never matches a *value*, it matches a *shape*. – Matthieu M. Jan 15 '19 at 13:43
  • @MatthieuM. the "exception of literal patterns" is why it would make some kind of sense, though. This being said, I'm not against a more high level explanation. – Denys Séguret Jan 15 '19 at 13:52
  • I wonder whether `match ()` would be cleaner than `match x`. It would make obvious the `match` here is just hiding a if/else bag – Denys Séguret Jan 15 '19 at 14:20
  • The big question, though, is what use a `match` then? An `if/else` cascade would work as well. Unrelated: you should not need parenthesis around the condition of `if`. – Matthieu M. Jan 15 '19 at 14:24
  • @MatthieuM Literals are not the only values that can occur in patterns. Constants are allowed as well, and so are dataless enum variants. – Sven Marnach Jan 15 '19 at 20:55
  • @SvenMarnach: A dataless enum variant is just a special case of pattern-matching on an enum, though. Good point about constants, with the advent of const fns, this means non-builtin values. – Matthieu M. Jan 16 '19 at 07:43