Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does `mut` work when matching on a mutable reference?

Tags:

match

rust

In the below program I am trying to understand the intricacies of the match statements when mut, & do come in. Beyond that there is no other scope in terms of any functionality.

To figure out the type of the variable, I used the variable to call a function checkout(n:i32). The compiler now will complain that checkout expects i32, but whereas the program is passing some other type. I am a newbie and this was the one way i thought we could figure out types of a variable which we don't explicitly mention.

fn checkout (k5:i32) {}

fn main() {
    let k5 = "learning rust".to_string();
    let k1 = Some(k5);
    match &mut k1 {
        Some(mut n) => {
            checkout(n);
            println!("the idea is {} {} ", n, n);
        }
        None => {}
    }
}

If I compile the program, the following error message is got

error[E0308]: mismatched types
 --> suds12.rs:9:35
  |
9 |           Some(mut n)=> {checkout(n);println!("the idea is {} {} ",n,n);},
  |                                   ^ expected `i32`, found struct `String`

The above clearly demonstrates that when mut n is present within Some, then the type of n is found to be that of String.

However if the program changes from Some (mut n) to Some(n), then the type of n is said to be &mut string. This can be again seeing by compiling the program with Some(n) and the error message is given below

error[E0308]: mismatched types
 --> suds12.rs:9:31
  |
9 |           Some(n)=> {checkout(n);println!("the idea is {} {} ",n,n);},
  |                               ^ expected `i32`, found `&mut String`

Here we can easily see that n is of type &mut String.

Why this is so?

like image 852
Sudarsan Avatar asked Apr 29 '26 18:04

Sudarsan


1 Answers

The confusion why Some(n) binds n to &mut String but Some(mut n) binds n to String is due to how match ergonomics were implemented.

Prior to this, match arms for references had to be much more explicit:

let mut k = Some("string".to_string());
match &mut k {
    &mut Some(ref mut x) => {},
    &mut None => {},
};

compile with version 1.25.0 or prior to test out the behavior

Lets focus on all the potential bindings for x:

  • x: would bind to the value directly, yielding a String
  • ref x: would bind to the value by reference, yielding a &String
  • ref mut x: would bind to the value by mutable reference, yielding a &mut String
  • mut x: is the same as x, it would bind to the value directly, yielding a String, with the only difference that n can be mutated

This understandably was tedious to write so RFC 2005: Match Ergonomics was designed to make the typical cases simpler to use. To accomplish that, it introduced binding modes where if the value was being pattern-matched on was a immutable or mutable reference, it would automatically infer bindings to x to be ref x or ref mut x respectively. So the above code could now be written as:

let mut k = Some("string".to_string());
match &mut k {
    Some(x) => {},
    None => {},
};

Much nicer.

However, the original syntax still exists and is usable even with the new binding modes in effect. For example, you can still use ref in a binding on a value to only bind to its reference. Or if you're already matching on a mutable reference you can use just ref to override that the binding to be immutable instead of mutable. Using any of ref/ref mut/mut would override the binding mode.

Do you see where this is going? Using Some(x) will use the ref mut binding mode since it is being matched on a &mut Option<_> and therefore bind x to &mut String. But using Some(mut x) the binding mode is overridden and will therefore bind x to String directly, with x being mutable.

See also:

  • Why does pattern matching on &Option<T> yield something of type Some(&T)?
  • Why is `ref` used instead of an asterisk in pattern matching?
  • Weird type when pattern matching references
  • Rust issue: Match ergonomics means bindings have different types inside and outside of patterns
like image 199
kmdreko Avatar answered May 02 '26 05:05

kmdreko



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!