I am confused as to why I am allowed to match to Some(ref mut y) in the first match statement if it's not actually a &mut in the tuple. Can someone please explain what is going on here so I can learn?
struct A {
x: Option<i32>,
}
fn main(){
let mut a = A{ x: Some(1) };
let b: &mut A = &mut a;
let o: Option<i32> = None;
match (b.x, o) {
(Some(ref mut y), None) =>{
println!("y was {}", y);
*y +=1;
println!("y is now {}", y);
},
_ => {}
}
match b.x {
Some(ref mut y) =>{
println!("y was {}", y);
*y +=1;
println!("y is now {}", y);
},
_ => {}
}
println!("a.x={:?}", a.x);
}
ref mut means that y is bound to the location of b.x as a mutable reference, rather than moving (or copying) b.x to a new location that y then owns. I think the reference explains it quite well, if you read from Patterns - The Rust Reference onwards, including the binding modes section.
Then which b.x is y bound to in the first match statement? As it is clearly not bound to the b.x I thought it was since it is not modifying the value of b.x.
Ah sorry, Option<i32> implements Copy, so when you create the tuple (b.x, o), you do copy b.x to a new location. This happens before the pattern matching. If you instead reborrow b.x when creating the tuple, your code works as expected:
struct A {
x: Option<i32>,
}
fn main(){
let mut a = A{ x: Some(1) };
let b: &mut A = &mut a;
let o: Option<i32> = None;
match (&mut b.x, o) {
(Some(y), None) =>{
println!("y was {}", y);
*y +=1;
println!("y is now {}", y);
},
_ => {}
}
match b.x {
Some(ref mut y) =>{
println!("y was {}", y);
*y +=1;
println!("y is now {}", y);
},
_ => {}
}
println!("a.x={:?}", a.x);
}
Yes, I arrived at that solution to my problem as well, but after reading the docs I still did not understand why the first version was matching Some(ref mut y) if the first element of the tuple was not a &mut. It is just a misunderstanding on my part on what ref mut means I guess... I thought it would only match if the value inside the Option was a mutable reference. If creating the tuple copies b.x, then clearly the first element of the tuple is not a mutable reference. Hence the confusion on my part.
Yes, well, ref mut is a binding mode independent of whether the T inside the Option<T> is a mutable reference or not. Some(ref mut y) will create a mutable reference y to the value inside the Option, if possible. If not—because the location is not mutable—you'll get a compile time error.
I don't know if this is documented, but the reason is that temporary objects are mutable, which was surprising to me, given that Rust follows "immutable by default" for variables.
The (b.x, o) creates a temporary, mutable object. It's as if you wrote: