Is there any difference between matching on a reference to a pattern or a dereferenced value?

Yes, these are the same to the compiler. In this case, there’s not much benefit. The real benefit comes from the match equivalent:

fn func(data: &Foo) {
    match data {
        &Foo::One => {}
        &Foo::Two => {}
        &Foo::Three => {}
    }
}

Here, you only have to place a single dereference, not 3 references in the patterns:

fn func(data: &Foo) {
    match *data {
        Foo::One => {}
        Foo::Two => {}
        Foo::Three => {}
    }
}

And since Rust 1.26, you don’t even have to dereference the expression being matched on:

fn func(data: &Foo) {
    match data {
        Foo::One => {}
        Foo::Two => {}
        Foo::Three => {}
    }
}

That’s why it’s the idiomatic choice.

The if let concept is just an extension from this.


You can’t always dereference the value. If you tried to do the same thing for a pair of items:

fn func(data: &Foo, data2: &Foo) {
    match (*data, *data2) {
        (Foo::One, _) => {}
        (Foo::Two, _) => {}
        (Foo::Three, _) => {}
    }
}

You get the error

error[E0507]: cannot move out of borrowed content
 --> src/main.rs:8:12
  |
8 |     match (*data, *data2) {
  |            ^^^^^ cannot move out of borrowed content

In this case, you can use the reference form:

fn func(data: &Foo, data2: &Foo) {
    match (data, data2) {
        (&Foo::One, _) => {}
        (&Foo::Two, _) => {}
        (&Foo::Three, _) => {}
    }
}

Or, since Rust 1.26, perform some implicit references:

fn func(data: &Foo, data2: &Foo) {
    match (data, data2) {
        (Foo::One, x) => {}
        (Foo::Two, _) => {}
        (Foo::Three, _) => {}
    }
}

Leave a Comment