You have read the lifetime in Rust. Now you are ready to learn how the lifetime is implemented in a method definition.
If you have not read lifetime in Rust yet, you can go here.
Method Definition in Rust
Let’s write a method definition in Rust for learning reference down the road.
struct StringCompare { origin: &str, } impl StringCompare { fn longestString(&self, x: &str) -> &str { return self.origin; } }
In the above code, you have a
StringCompare
struct that has an origin
of type &str
and a method that accepts a &str
parameter.The
longestString
should compare origin
and x
length and return the longest string. But for now, you will just return the origin
string to learn how lifetime inference works in method definition.Lifetime inference when returning self.origin
First Rule Check: Assign different lifetime to each parameter
In this lifetime inference, the compiler will first assign a different lifetime to each reference parameter.
&self
will have its lifetime as written in StringCompare
struct StringCompare<'a> { origin: &'a str, } impl<'a> StringCompare<'a> { fn longestString<'b>(&self, x: &'b str) -> &str { return self.origin; } }
Third Rule Check: Assign &self
lifetime to output lifetime
Because
&self
exists, the output will have the same lifetime.impl<'a> StringCompare<'a> { fn longestString<'b>(&self, x: &'b str) -> &'a str { return self.origin; } }
Now every reference has a lifetime. There is no ambiguity, and the compiler can continue compiling your code.
Lifetime inference when return the longest string
Now you need to update the
longestString
implementation to compare origin
with x
and return the longest string.impl<'a> StringCompare<'a> { fn longestString<'b>(&self, x: &'b str) -> &'a str { if self.origin.len() > x.len() { self.origin } else { x } } }
When you compile above code, you will find this error
5 | impl<'a> StringCompare<'a> { | -- lifetime `'a` defined here 6 | fn longestString<'b>(&'a self, x: &'b str) -> &'a str { | -- lifetime `'b` defined here ... 10 | x | ^ method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` | = help: consider adding the following bound: `'b: 'a`
The error is quite clear. It says “method was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b`" while pointing to the
x
variable in the else block.This is because
'a
and 'b
have different lifetimes, and 'b
probably will not live as long as 'a
.To fix the issue, you can assign
'a
and remove 'b
lifetime.impl<'a> StringCompare<'a> { fn longestString(&self, x: &'a str) -> &'a str { if self.origin.len() > x.len() { self.origin } else { x } } }
That way, you tell the compiler that whatever reference is passed to
x
must live as long as our StringCompare
instance.Conclusion
Working with lifetime is tricky. There are pitfalls waiting around the corner. By understanding and following the three rules of compiler lifetime inference, you can always understand what error it reports. You can then solve that.