Consider the following code, where a reference to a root type R is wrapped. Also stored is some type N(avigate), which knows how to dereference R for T.
use std::ops::Deref;
struct Wrapper<'r, R, N, T>
where
N: Fn(&'r R) -> &T,
T: 'static,
{
r: &'r R,
n: N,
}
impl<'r, R, N, T> Deref for Wrapper<'r, R, N, T>
where
N: Fn(&'r R) -> &T,
T: 'static,
{
type Target = T;
fn deref(&self) -> &T {
let r: &'r R = self.r;
let t: &'r T = (self.n)(r);
t
}
}
Now, if we change our reference type r: &'r R, to be mutable r: &'r mut R, it no longer works:
use std::ops::Deref;
struct Wrapper<'r, R, N, T>
where
N: Fn(&'r R) -> &T,
T: 'static,
{
r: &'r mut R,
n: N,
}
impl<'r, R, N, T> Deref for Wrapper<'r, R, N, T>
where
N: Fn(&'r R) -> &T,
T: 'static,
{
type Target = T;
fn deref(&self) -> &T {
let r: &'r R = self.r;
let t: &'r T = (self.n)(r);
t
}
}
Error:
error[E0312]: lifetime of reference outlives lifetime of borrowed content...
--> src/lib.rs:21:24
|
21 | let r: &'r R = self.r;
| ^^^^^^
|
note: ...the reference is valid for the lifetime 'r as defined on the impl at 13:6...
--> src/lib.rs:13:6
|
13 | impl<'r, R, N, T> Deref for Wrapper<'r, R, N, T>
| ^^
note: ...but the borrowed content is only valid for the anonymous lifetime #1 defined on the method body at 20:5
--> src/lib.rs:20:5
|
20 | / fn deref(&self) -> &T {
21 | | let r: &'r R = self.r;
22 | | let t: &'r T = (self.n)(r);
23 | | t
24 | | }
| |_____^
We get a better error message with nll:
error: lifetime may not live long enough
--> src/lib.rs:21:16
|
13 | impl<'r, R, N, T> Deref for Wrapper<'r, R, N, T>
| -- lifetime `'r` defined here
...
20 | fn deref(&self) -> &T {
| - let's call the lifetime of this reference `'1`
21 | let r: &'r R = self.r;
| ^^^^^ type annotation requires that `'1` must outlive `'r
I've annotated the lifetimes in deref to make sure i'm on the same track as the compiler about the lifetimes. The nll message is particulary interesting, because it says that it requires &self to outlive 'r.
But that doesn't make sense to me, since if we annotate the lifetimes on deref, it should look like this:
fn deref<'1>(&'1 self) -> &'1 T;
And rather require that 'r: '1, which is implicitly given by Wrapper<'r, ...>
This intuition seems to hold in the first example, but not in the second with the immutable reference.
So two questions unfold for me:
- Why does it make a difference if
self.ris immutable or not? I can't accessrmutably anyway, since&selfis immutable. - Is
1.a fundamental restriction, or can the code be annotated in a way to tell rustc what i want to do?
'rwill never be shortened for the callderef(). In both the casesself.rwill remain borrowed for'rlifetime. However with mutable reference, the compiler is basically telling you that sinceself.ris borrowed (mutable references are reborrowed when passed as function arguments) inderef(), it also needsselfto remain borrowed for atleast'rlifetime. So in the minimal version code above, if you make the change from&selfto&'r self, it compiles.