Well, the function is borrow-checked at the definition site. &str
is Copy
, so you can copy out the &'a str
. You don't need 'a
on the outer reference:
fn foo(&self) -> &'a str {
self.s
}
But forcing &'a self
doesn't cause any problems when it comes to borrow checking the function body, either. The &'a str
can be copied out from behind any other reference.
So I guess your question is really about the call site:
let f = Foo{s:"123"} ;
{
let bf = &f;
let s = bf.foo();
}
Let me clean this up a little first.
The lifetime on Foo { .. }
is probably inferred, so let's get rid of that as I think this is what you are asking about. Also, incidentally, the inner scopes aren't doing anything here. All that happens at the end of the inner scope is that bf
and s
(shared references) go out of scope, which is almost always a no-op.
let f = Foo::<'static> {s:"123"} ;
let bf = &f;
let s = bf.foo();
And this still compiles.
&'static str
is a subtype of &'a str
(for any other lifetime 'a
), which is why &'static str
can coerce to &'a str
. Similarly, Foo<'static>
is a subtype of Foo<'a>
.
More generally, &'long T
is a subtype of &'short T
.
Additionally, the T
in &T
is covariant. Which means that if U
is a subtype of T
, &'x U
is a subtype of &'x T
. And thus &'longer_than_x U
is also a subtype of &'x T
.
So for example, both of these assignments can work due to coercing to the supertype:
// Infer the reference lifetime (unavoidable) and also infer the
// lifetime that is a parameter on `Foo`
let bf: &'_ Foo<'_> = &f;
// Infer the reference lifetime but keep the `Foo` parameter `'static`
let bf: &'_ Foo<'static> = &f;
And in either case, when you make the call to the foo
method -- which requires the lifetimes to be the same -- the parameter on Foo
can coerce down to be equal to the reference lifetime.
That is, your &'x Foo<'static>
can coerce down to any &'a Foo<'a>
where 'x: 'a
.
That's why the call succeeds.
Here it is in code form.