Reputation: 605
This code is based on the example code in the Rust book in the lifetimes chapter. I was wondering how do the following two versions of the same method differ:
struct Important<'a> {
part: &'a str,
}
impl<'a> Important<'a> {
fn larger<'b>(&'b self, other: &'b str) -> &'b str {
if self.part.len() > other.len() {
self.part
} else {
other
}
}
}
versus
struct Important<'a> {
part: &'a str,
}
impl<'a> Important<'a> {
fn larger(&self, other: &'a str) -> &str {
if self.part.len() > other.len() {
self.part
} else {
other
}
}
}
I guess in the first version we are instructing the compiler that
Find a lifetime 'b
such that both &self
and the reference other
are valid during it (probably the shorter of the two lifetimes if they overlap)
Make sure that the returned reference is only used within that lifetime 'b
because outside it might become a dangling reference.
What does the second version of the code do? One of the lifetime elision rules in the Rust book says that in a struct method the returned reference is assigned the lifetime of the &self
parameter (which is 'a
here), so are we saying that other
should also be valid for the same lifetime as the &self
parameter, which is the lifetime 'a
?
Semantically, is this the same code or could these versions behave differently depending of the lifetimes of other
and the struct?
Upvotes: 1
Views: 480
Reputation: 15115
What does the second version of the code do? One of the lifetime elision rules in the rust book says that in a struct method the returned reference is assigned the lifetime of the &self parameter (which is
'a
here), so are we saying that other should also be valid for the same lifetime as the&self
parameter, which is the lifetime'a
?
That's slightly inaccurate, the lifetime of &self
in the second example is not 'a
but it is bounded by 'a
. The second example would desugar to this if we expand it by reversing Rust's lifetime elision rules:
struct Important<'a> {
part: &'a str,
}
impl<'a> Important<'a> {
fn larger<'b>(self: &'b Important<'a>, other: &'a str) -> &'b str {
if self.part.len() > other.len() {
self.part
} else {
other
}
}
}
The reason why self is bounded by 'a
is because &'b Important<'a>
implies 'b: 'a
or in plain terms "'a
outlives 'b
" which must be true otherwise the reference may get invalidated. If we expand the first example the type of self
again becomes &'b Important<'a>
. The only difference between the first and second example is the type of other
, in the first it's &'b str
and in the second it's &'a str
but that's an irrelevant detail since the return value has the type &'b str
which is constrained by the 'b
lifetime and we know that 'b: 'a
so functionally both examples are the same.
Upvotes: 3