How does Rust pattern matching determine if the bound variable will be a reference or a value?

RFC 2005 (a.k.a. match ergonomics) introduced the rule.

Before the change was implemented, there were 2 ways to write this match.

  1. Match on self and prefix each pattern with & to “destructure” the reference.

    fn tail(&self) -> Option<&Foo> {
        match self {
            &Cons(_, ref item) => Some(item),
            &Nil => None,
        }
    }
    
  2. Match on *self and don’t prefix each pattern with & (because *self is not a reference).

    fn tail(&self) -> Option<&Foo> {
        match *self {
            Cons(_, ref item) => Some(item),
            Nil => None,
        }
    }
    

Yet, in both cases, we need to write ref item, otherwise we’ll get error[E0507]: cannot move out of borrowed content.

However, in the match you’ve written, the expression being matched is a reference (type &List) but the patterns are not reference patterns (as in 1. above). This is where match ergonomics kick in: the rule says that when a reference is matched with a non-reference pattern, the bindings within that pattern bind by reference rather than by value (i.e. as if they were prefixed with ref).

Leave a Comment