Reputation: 6094
I am playing with this code to to understand lifetimes and elision better. This code compiles.
struct Bytes<'a>(&'a [u8]);
impl<'a> Bytes<'a> {
fn first_two<'b>(self: &'b Bytes<'a>) -> &'b [u8]
where 'b: 'a
{
&self.0[..2]
}
}
How can the where
bound 'b: 'a
be acceptable for self
? Shouldnt it always be the other way for self
to be valid?
And the return value points to slice inside Bytes
whose lifetime is 'a
. So how can the output have lifetime 'b
if 'b
can outlive 'a
?
Upvotes: 3
Views: 605
Reputation: 155246
It's important to notice that the code compiles even when you remove the where
clause altogether, which should remove any relationship between the two lifetimes. Why is that allowed?
I think what happens is that the very existence of a self: &'b Bytes<'a>
parameter implies the constraint of 'a: 'b
. For any Bytes<'a>
value to exist in the first place, the caller must ensure that 'a
referenced by Bytes
lives at least as long as the Bytes
value itself - hence 'a: 'b
. In other words, returning &'b [u8]
actually reduces the lifetime compared to the original 'a
, which is always allowed.
To return to your code, when you further add 'b: 'a
, you are telling Rust that in addition to the requirement of 'a
living at least as long as 'b
, also 'b
has to live at least as long as 'a
. In other words, 'b
and 'a
must be the same lifetime - which again makes it ok to return &'b [u8]
, as it's the same as &'a [u8]
.
How can the where bound
'b: 'a
be acceptable forself
? Shouldnt it always be the other way for self to be valid?
Precisely - it should be the other way around for self
to be valid, and that makes it ok to return &'b [u8]
. As argued above, adding the seemingly "inverse" constraint doesn't make the first one go away, it just makes the relationship stricter. (It's like knowing that a >= b
for two numbers, and further stipulating that b <= a
- the two just boil down to a == b
.)
Upvotes: 4