Reputation: 985
I have an Option<&mut T>
and want to access the contained reference multiple times, like so:
fn f(a: Option<&mut i32>) {
if let Some(x) = a {
*x = 6;
}
// ...
if let Some(x) = a {
*x = 7;
}
}
fn main() {
let mut x = 5;
f(Some(&mut x));
}
That doesn't work, because if let Some(x) = a
moves the reference value out of the Option, and the second if let Some(x) = a
will result in a compiler error. Without the second if let ...
, this works flawlessly, so a
doesn't have to be mutable.
The following:
if let Some(ref x) = a {
**x = 6;
}
gives an error: "assignment into an immutable reference".
This would work:
fn f(mut a: Option<&mut i32>) {
if let Some(ref mut x) = a {
**x = 6;
}
if let Some(ref mut x) = a {
**x = 7;
}
}
The mut a
is necessary, otherwise I get an error "cannot borrow immutable anonymous field (a:std::prelude::v1::Some).0
as mutable". But this feels wrong: a
shouldn't have to be mutable, because I'm not modifying it (see above).
What's the correct solution?
My problem is different from the one in How to pass `Option<&mut ...>` to multiple function calls without causing move errors?. I want to mutably dereference the reference in an Option<&mut T>
multiple times, while the other one wants to pass an Option
to multiple function invocations. The solutions to the other question are not applicable to my situation.
Upvotes: 8
Views: 1028
Reputation: 88576
What about this?
fn f(a: Option<&mut i32>) {
if let Some(&mut ref mut x) = a {
*x = 6;
}
// ...
if let Some(&mut ref mut x) = a {
*x = 7;
}
}
In this case, a
doesn't need to be mutable.
The &mut ref mut
feels a bit awkward, but it makes sense: first we remove a &mut
by destructuring and then take a mutable reference to the value again. It's more obvious when we don't use the Option
:
let mr: &mut Vec<u32> = &mut vec![];
{
let &mut ref mut a = mr;
a.push(3);
}
mr.push(4);
This also works. The third (special) line is equivalent to:
let a = &mut *mr ;
// ^^^----- this is an lvalue of type `Vec<u32>`
// ^^^^^^^^^^^^----- together it's of type `&mut Vec<u32>` again
In the Option
case, we can't use the &mut *X
version, but need to do all of it inside of the pattern. Thus the &mut ref mut x
.
Upvotes: 4