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?
The confusion why
Some(n)bindsnto&mut StringbutSome(mut n)bindsntoStringis due to how match ergonomics were implemented.Prior to this,
matcharms for references had to be much more explicit: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 aStringref x: would bind to the value by reference, yielding a&Stringref mut x: would bind to the value by mutable reference, yielding a&mut Stringmut x: is the same asx, it would bind to the value directly, yielding aString, with the only difference thatncan be mutatedThis 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
xto beref xorref mut xrespectively. So the above code could now be written as: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
refin a binding on a value to only bind to its reference. Or if you're already matching on a mutable reference you can use justrefto override that the binding to be immutable instead of mutable. Using any ofref/ref mut/mutwould override the binding mode.Do you see where this is going? Using
Some(x)will use theref mutbinding mode since it is being matched on a&mut Option<_>and therefore bindxto&mut String. But usingSome(mut x)the binding mode is overridden and will therefore bindxtoStringdirectly, withxbeing mutable.See also: