Match doesn't seem to work exhaustively


match doesn’t make a compile error for unknown value or non-exaustive matches. Is this (1) my fault, (2) a feature or (3) a bug?

fn main() {
    enum Foo1 {
    let a = Foo1::bar2;
    match a {
        x => {
            println!("{:?}", x);

On Playground


The answer is (1).
The pattern x matches any possible value of a, and so the statement println!("{:?}", x); is surely executed. The exhaustion rule means that it is forbidden a situation in which no arm matches the expression.



Although I see the use case of this feature, this seems to be very error-prone to me… Anyway I’ll try to change my mind.


Why do you think it’s error-prone? Could you show one or more errors caused by it?


I mean “error-prone” it does not help to prevent my (programmer) errors. Because arbitrary typing mistake can be treated as valid input of “match-any” regardless of programmer’s intention. Here’s another example.

enum Foo1 { bar2, bar3, bar4 }
use Foo1::*;

fn main() {
    let a = bar2;
    let b = match a {
        bar2 => "a",
        bar => "b",
    println!("{}", b);   

Programmer made several mistake here, and this kind of error is usually happen for me. Anyway, I discovered that Rust compiler warns about unused variable bar in this case, so I think this wouldn’t be a big problem as like I imagined.


Rust also has a very useful error if you use a variant name as the identifier.

enum X { A, B, C }

fn main() {
    let x = X::A;
    println!("{}", match x {
        A => {
            let _ = A;
warning[E0170]: pattern binding `A` is named the same as one of the variants of the type `X`
 --> src/
7 |         A => {
  |         ^
  = help: if you meant to match on a variant, consider making the path in the pattern qualified: `X::A`


This is partly why enum variants are written in CapitalCamel case, and variables are written in lower_snake case. This is also why it’s a good idea to (where reasonable), avoid doing use Foo::*;, and instead writing Foo::Bar2, etc.. Finally, I’d be stunned if there wasn’t a clippy lint to protect against this. Also, this is only an issue if you make this mistake on the last arm of a match; doing this on a previous one should trigger an “unreachable arm” error.

It’s not ideal, no, but the odds of actually making this mistake in practice while writing Rust code idiomatically seems pretty low.


In addition, if a variable is used as pattern, and such variable is not used in the right side of the arm, an unused variable warning is issued.


Incidentally, you use this feature of pattern matching every time you create a new variable; let takes a pattern. names like this are irrefutable patterns, as they always match. let x = 5 is doing the same thing as the match arm.