Consider this toy code:
struct X {
x: usize,
times_accessed: usize,
}
impl X {
fn get(&mut self) -> usize {
self.times_accessed = self.times_accessed + 1;
self.x
}
}
struct Y {
y: usize,
max_access: usize,
option_x: Option<X>,
}
impl Y {
fn get_x(&mut self) -> Option<usize> {
match self.option_x {
Some(ref mut some_x) => {
let result = some_x.get();
if some_x.times_accessed == self.max_access {
self.option_x = None;
}
Some(result)
}
None => {
println!("option_x is not initialized! try calling Y::init_x");
None
}
}
}
fn init_x(&mut self, x_val: usize, max_allowed_access: usize) {
self.max_access = max_allowed_access;
self.option_x = Some(X {
x: x_val,
times_accessed: 0,
});
}
}
fn main() {
println!("hello world!");
}
I haven't bothered using Y
in the main function, because the compiler doesn't need me to do that to point out that the borrow checker would not be satisfied with the implementation for Y::get_x
:
error[E0506]: cannot assign to `self.option_x` because it is borrowed
--> src/main.rs:26:21
|
22 | Some(ref mut some_x) => {
| -------------- borrow of `self.option_x` occurs here
...
26 | self.option_x = None;
| ^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `self.option_x` occurs here
I understand the issue from the borrow checker's perspective, and I can come up with a very simple fix: copy the value from some_x
into result
(am I not already doing that, after all, result isn't a reference, and usize
has the Copy
trait), and then "drop the reference" to some_x
(would it be using drop(some_x);
, so I can modify option_x
? A version of that is presented here, but still doesn't work:
fn get_x(&mut self) -> Option<usize> {
match self.option_x {
Some(ref mut some_x) => {
let result = some_x.get();
if some_x.times_accessed == self.max_access {
drop(some_x);
self.option_x = None;
}
Some(result)
}
None => {
println!("option_x is not initialized! try calling Y::init_x");
None
}
}
}
What should one do?