Default match bindings

Minimum Rust version: 1.26

Have you ever had a borrowed Option<T> and tried to match on it? Youprobably wrote this:

  1. let s: &Option<String> = &Some("hello".to_string());
  2. match s {
  3. Some(s) => println!("s is: {}", s),
  4. _ => (),
  5. };

In Rust 2015, this would fail to compile, and you would have to write thefollowing instead:

  1. // Rust 2015
  2. let s: &Option<String> = &Some("hello".to_string());
  3. match s {
  4. &Some(ref s) => println!("s is: {}", s),
  5. _ => (),
  6. };

Rust 2018, by contrast, will infer the &s and refs, and your originalcode will Just Work.

This affects not just match, but patterns everywhere, such as in letstatements, closure arguments, and for loops.

More details

The mental model of patterns has shifted a bit with this change, to bring itinto line with other aspects of the language. For example, when writing afor loop, you can iterate over borrowed contents of a collection byborrowing the collection itself:

  1. let my_vec: Vec<i32> = vec![0, 1, 2];
  2. for x in &my_vec { ... }

The idea is that an &T can be understood as a borrowed view of T, andso when you iterate, match, or otherwise destructure a &T you get aborrowed view of its internals as well.

More formally, patterns have a "binding mode," which is either by value(x), by reference (ref x), or by mutable reference (ref mut x). In Rust2015, match always started in by-value mode, and required you to explicitlywrite ref or ref mut in patterns to switch to a borrowing mode. In Rust2018, the type of the value being matched informs the binding mode, so thatif you match against an &Option<String> with a Some variant, you are putinto ref mode automatically, giving you a borrowed view of the internaldata. Similarly, &mut Option<String> would give you a ref mut view.