Below is a simplified version of a bit of code I'm struggling with.
enum Bar {
NotReady,
Ready(u64),
}
struct Foo {
bar: Bar,
}
impl Foo {
fn baz(&mut self) -> Option<&u64> {
match &mut self.bar {
Bar::NotReady => {
self.bar = Bar::Ready(123);
None
}
Bar::Ready(val) => Some(val),
}
}
}
The compiler error I get is:
105 | fn baz(&mut self) -> Option<&u64> {
| - let's call the lifetime of this reference `'1`
106 | match &mut self.bar {
| ------------- `self.bar` is borrowed here
107 | Bar::NotReady => {
108 | self.bar = Bar::Ready(123);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ `self.bar` is assigned to here but it was already borrowed
...
111 | Bar::Ready(val) => Some(val),
| --------- returning this value requires that `self.bar` is borrowed for `'1`
I don't completely understand this error message. Can someone please explain it and offer an idiomatic way of accomplishing something like this?
Thanks for the reply but this doesn't quite work for me.
You have made one other change, you are no longer return a reference to u64. In my case, I have to return a reference as the object stored there cannot be cloned / copied.
Here's an explanation of how the current borrow checker doesn't have enough flow sensitivity to make the borrow duration of the &mut self.bar be either short or long based on which match branch will be taken. The next borrow checker should handle the original code.
In contrast, @firebits.io's latest solution defers creating a borrow until a particular branch is decided, which the current borrow checker can handle.
Here's a link to the documentation about bindings in match expressions, and here's the link to the documentation for the ref keyword.
My thought process is just to read what the compiler is saying and adjust the code accordingly, one step at a time:
Using your original version, the compiler error showed that self.bar was borrowed, and Rust's borrow checker rule known as "aliasing XOR mutability" prevents us from doing what you had attempted. Thus I started changing your code by removing that borrow.
If in my final code you remove the ref keyword and try to return Option<Uncopyable> instead, you'll notice that the compiler will complain about the value being moved (due to how bindings work in match patterns, as mentioned in the link I mentioned before). Thus I added the ref keyword to the pattern in order to only borrow the value instead of moving it.