0

I have the following piece of code, which compiles using rustc v1.36:

enum Number {
    Integer(i32),
    Real(f32),
}

fn foo1(number: &mut Number) {
    if let Number::Integer(n) = number {
        let _y: &mut i32 = n;
    }
}

fn foo2(number: &mut Number) {
    if let &mut Number::Integer(ref mut n) = number {
        let _y: &mut i32 = n;
    }
}

Funny enough, I can understand how 'foo2' does the matching, but not so for 'foo1', while 'foo1' is the kind of code you will see in any Rust project. Can someone explain how the matching syntax in these 2 is equivalent? And thus it extend to other code (structures?) as well?

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
Arne J
  • 415
  • 2
  • 9
  • Rust is annoying because it's hard to make code compile but compiled mean correct code. Why don't you like when code compile ? This feature was added recently to increase life quality. That just the more infer thing. This is possible because Rust get a more precise borrow checker. `number` is `&mut` so the infer tool match ref and mut. – Stargateur Aug 16 '19 at 13:00
  • Just to clarify, this has nothing to do with the borrow checker - it's due to the [match ergonomics RFC](https://rust-lang.github.io/rfcs/2005-match-ergonomics.html), which added auto-dereferencing to pattern matching. – Joe Clay Aug 16 '19 at 13:46
  • Thanks @JoeClay this is the first page I've seen to explain this behavior. You should provide it as an answer to my question. – Arne J Aug 16 '19 at 14:03

1 Answers1

2

This functionality was added in Rust 1.26, and is called 'default binding modes' (or 'match ergonomics', after the RFC that proposed it). It effectively allows pattern matching to automatically dereference values, and to add ref and ref mut to variable bindings where needed.

The rules for this behaviour are discussed in detail in the RFC, but it effectively boils down to:

  • Variable bindings within a pattern can be resolved in one of three modes:
    • 'move' (the default), which will move the value.
    • 'ref', which will immutably reference the value.
    • 'ref mut', which will mutably reference the value.
  • When a variable binding is encountered within a pattern without an explicit ref, mut or ref mut, the current binding mode will be used.
  • When a reference is pattern matched using a non-reference pattern:
    • The value will be auto-dereferenced.
    • The binding mode may change for any nested patterns:
      • If the type of the reference is &T, the binding mode will change to 'ref'.
      • If the type of the reference is &mut T and the current binding mode is not 'ref', the binding mode will change to 'ref mut'.

This may sound complicated, but as you can see from the end result, it tends to line up with how you'd intuitively write the match!

Joe Clay
  • 33,401
  • 4
  • 85
  • 85