Hello, I'm once again confused by the borrow checker.
Here's a toy example that fails to compile:
struct Foo<T>(T);
impl <T> Foo<T> {
fn error(&mut self) -> &T {
if let Some(v) = self.get() {
v
} else {
&self.0
}
}
fn works(&mut self) -> &T {
&self.0
}
fn also_works(&mut self) -> &T {
self.get().unwrap()
}
fn get(&mut self) -> Option<&mut T> {
// Pretend this function does something reasonable
// and can return either Some or None
panic!();
}
}
Both works()
and also_works()
compile, but error()
doesn't - why?
The error message implies that the mutable borrow initiated by get()
extends for the whole length of error()
, even though its contents are only used in the first branch.
I've attempted rewriting the function in the following way that should preserve its semantics, while making the scopes of borrows clearer:
fn error(&mut self) -> &T {
{
let opt = self.get();
if let Some(v) = opt {
return v;
}
}
let r = &self.0;
return r;
}
This looks especially strange to me: opt
is out of scope by the time let r = &self.0
is reached, yet the compiler insists that the mutable borrow of self
initiated by get()
is still active at that point.
Does returning a reference cause its lifetime to extend? Why? I'd expect the opposite to happen - if the body of the function past the return is still executing, then the return didn't occur, so the reference hasn't been shared with the outside world and should be dropped by now.
I feel like either I'm missing something obvious, or it's a borrow checker limitation and I just need to work around it.