I have a number of inter-related questions I'd like to ask around this topic, which I hope is ok.
I started with the following code:
use std::cell::RefCell;
struct SomeStruct {
x: u64,
y: u64,
}
fn process_ss(ss: Option<&mut SomeStruct>) {
let x = match ss {
Some(ss) => Some(&mut ss.x),
None => None,
};
//do mutable processing on x
let y = match ss {
Some(ss) => Some(&mut ss.y),
None => None,
};
//do mutable processing on y
}
fn main() {
let mut ss = SomeStruct {x: 1, y: 2};
process_ss(Some(&mut ss));
}
If the option is in fact Some
, I was hoping to get a mutable ref for x and y out of it, and pass it further down for processing.
This however produces an error:
Some(ss) => Some(&mut ss.x),
| -- value moved here
...
17 | Some(ss) => Some(&mut ss.y),
| ^^ value used here after move
|
= note: move occurs because value has type `&mut SomeStruct`, which does not implement the `Copy` trait
help: borrow this field in the pattern to avoid moving `ss.0`
|
First question - why is rust complaining I'm moving the value? Surely what's inside the option is a reference, not a value?
After a bunch of tinkering, I arrived at:
fn process_ss(mut ss: Option<&mut SomeStruct>) {
let x = match ss {
Some(ref mut ss) => Some(&mut ss.x),
None => None,
};
//do mutable processing on x
let y = match ss {
Some(ref mut ss) => Some(&mut ss.y),
None => None,
};
//do mutable processing on y
}
- which works.
Second question - I don't fully understand what the mut
in front of ss
is doing. It seems we now have a mutable function parameter, which contains an option, which may contain a mutable reference? Why is this necessary?
Third and final question - is the way I solved it considered appropriate, or is there a better, more elegant way?
One other option I tried was this:
let (x, y) = match ss {
Some(ss) => (Some(&mut ss.x), Some(&mut ss.y)),
None => (None, None),
};
which leads to cannot borrow
*ss as mutable more than once at a time