I try to change the value function of the Cacher to allow it to return a reference of the value that is in the cache I did it with if/else statement with success:
impl<T,P,R> Cacher<T,P,R>
where T : Fn(P) -> R
{
fn value(&mut self, param: P) -> &R {
if self.value.is_some() {
self.value.as_ref().unwrap()
}
else {
let v = (self.calculation)(param);
self.value = Some(v);
self.value.as_ref().unwrap()
}
}
}
I tried to do it with pattern matching but without success and I'm completly stuck.
I tried the following:
fn value<'a>(&'a mut self, param: P) -> &'a R {
match &self.value {
Some(ref x) => x,
None => {
let v = (self.calculation)(param);
self.value = Some(v);
self.value.as_ref().unwrap()
}
}
}
But I have 2 errors:
error[E0506]: cannot assign to `self.value` because it is borrowed
--> src\main.rs:50:17
|
45 | fn value(&mut self, param: P) -> &R {
| - let's call the lifetime of this reference `'1`
46 | match &mut self.value {
| --------------- borrow of `self.value` occurs here
47 | Some(x) => x,
| - returning this value requires that `self.value` is borrowed for `'1`
...
50 | self.value = Some(v);
| ^^^^^^^^^^ assignment to borrowed `self.value` occurs here
error[E0502]: cannot borrow `self.value` as immutable because it is also borrowed as mutable
--> src\main.rs:51:17
|
45 | fn value(&mut self, param: P) -> &R {
| - let's call the lifetime of this reference `'1`
46 | match &mut self.value {
| --------------- mutable borrow occurs here
47 | Some(x) => x,
| - returning this value requires that `self.value` is borrowed for `'1`
...
51 | self.value.as_ref().unwrap()
| ^^^^^^^^^^ immutable borrow occurs here
I don't understand if it's a borrow issue or a lifetime issue.. or both...
Can someone explains?
Thank you
Well I fix it by matching self.value instead of &self.value
fn value(&mut self, param: P) -> &R {
match self.value {
Some(ref x) => x,
None => {
let v = (self.calculation)(param);
self.value = Some(v);
self.value.as_ref().unwrap()
}
}
I though match taking ownership of the value because I did not ask a reference on self.value. So returning a reference on the value owned in the match will not compile due to temporary variable but it's not the case...
I understand is that borrow or owership do not happened in the match line but in the 'case' line for each bracket, that explains the need of Some(ref x) to obtain a reference on the Option value instead of taking ownership. It explains why if I do Some(x) => &x the compiler says:
error[E0515]: cannot return reference to local variable `x`
--> src\main.rs:47:24
|
47 | Some(x) => &x,
| ^^ returns a reference to data owned by the current function
Is it possible to do the same by matching with &mut self.value? I don't know how.
match self.value /*: Option<R>*/ {
Some(x /*: R*/ ) => &x /*: &R*/, // good type, but returns borrow of local
We need to bind by reference
With match ergonomics
match &self.value /*: &Option<R>*/ {
Some(x /*: &R*/ ) => x /*: &R*/, // good type, all works well
this works because it is actually sugar for:
match &self.value /*: &Option<R>*/ {
&Some(ref x /*bind by ref to a R => &R*/ ) => x /*: &R*/,
// ^
// |
// +-- this dereferences `&self.value` to temporarily work on `self.value`;
// This is important, since `Some` / `None` is a discriminant of `Option`, not of `&Option`
In other words, this is also equivalent to
Your solution
match self.value /*: Option<R>*/ {
Some(ref x /*bind by ref to a R => &R*/ ) => x /*: &R*/,
we have "simplified the ampersands"
Yes, and it is the same idea, but using ref mut instead of ref:
match self.value /*: Option<R>*/ {
Some(ref mut x /*bind by ref mut to a R => &mut R*/ ) => x /*: &mut R*/,
or:
match &mut self.value /*: &mut Option<R>*/ {
&mut Some(ref mut x /*bind by ref mut to a R => &mut R*/ ) => x /*: &mut R*/,
or, with match ergonomics:
match &mut self.value /*: &mut Option<R>*/ {
Some(x /*: &mut R*/ ) => x /*: &mut R*/,
Thank you very much for the clarification.
The major point I don't understand is with the 'None' branch.
What I understand is:
match &mut self.value /* Mutable borrow occurs here */{
Some(x) => x, /* Return mutable borrow of self.value.'x' */
None => {
let v = (self.calculation)(param);
self.value = Some(v); /* Not working because self.value is already borrowed */
self.value.as_ref().unwrap() /* Same problem here */
}
}
Is there a way to retrieves the mutable borrow of self.value in 'None' branch?
I found a workaround but I need to borrow outside the match like this:
let mut_ref_of_value = &mut self.value;
match mut_ref_of_value {
Some(x) => x,
None => {
let v = (self.calculation)(param);
*mut_ref_of_value = Some(v);
mut_ref_of_value.as_ref().unwrap()
}
}
Ok after a deep research on the web I found this :
match &mut self.value {
Some(x) => x,
value_ref @ None => {
let v = (self.calculation)(param);
*value_ref = Some(v);
value_ref.as_ref().unwrap()
}
}
This is not very well documented, I found this in an old version of the book Patterns
It also appears here Match expressions - The Rust Reference but is totally ignored in the documentation.