Search code examples
rustpattern-matchingref

Pattern matching in rust and mutability


Let's say that I have an Option<String> and want to pattern match to get a mutable reference to the String. I can do the following (_a needs to be mutable):

  let mut _a: Option<String> = Some(String::from("foo"));
  if let Some(ref mut aa) = _a {
    aa.push_str("_");
    println!("aa: {:?}", aa)
  }

Now let's say that I have two Option<String> values that I want to pattern match over.

  let _b: Option<String> = Some(String::from("bar"));
  let _c: Option<String> = Some(String::from("baz"));
  if let (Some(ref mut bb), Some(ref mut cc)) = (_b, _c) {
    bb.push_str("_");
    cc.push_str("_");
    println!("bb: {:?}, cc: {:?}", bb, cc);
  }

Strangely, I can use ref mut in the patterns, even though neither _b nor _c are mutable, and I can mutate the strings. Why is that allowed here in this case? I'd expect this not to compile unless both _b and _c are declared as mutable similar to the first example above.

I think what may be happening is that a tuple is constructed in the pattern match, i.e. (_b, _c), and then some compiler magic allows the ref mut on the pattern that is "bound" to this tuple. Is that correct?

Rust version:

rustc 1.41.1 (f3e1a954d 2020-02-24)

Solution

  • The mut isn't necessary if the value is wrapped in a tuple, because the tuple is a new value (playground):

    let a = Some(String::from("foo"));
    if let (Some(mut aa),) = (a,) {
        aa.push_str("_");
        println!("aa: {:?}", aa)
    }