I'm implementing a trait for a reference type using a Rust older than 1.31. Why does Rust want an explicit lifetime when I tell it what reference type I'm implementing the trait for?
Here's a simple example. A struct Inches
, an implementation of the
Add
trait for &Inches
, and a function that uses that implementation.
(Rust playground link)
use std::ops::Add;
struct Inches(i32);
// this would work: impl<'b> Add for &'b Inches
impl Add for &Inches {
type Output = Inches;
fn add(self, other: &Inches) -> Inches {
let &Inches(x) = self;
let &Inches(y) = other;
Inches(x + y)
}
}
// lifetime specifier needed here because otherwise
// `total = hilt + blade` doesn't know whether `total` should live
// as long as `hilt`, or as long as `blade`.
fn add_inches<'a>(hilt: &'a Inches, blade: &'a Inches) {
let total = hilt + blade;
let Inches(t) = total;
println!("length {}", t);
}
fn main() {
let hilt = Inches(10);
let blade = Inches(20);
add_inches(&hilt, &blade);
}
Compilation fails with the following error:
error: missing lifetime specifier [E0106]
impl Add for &Inches {
^~~~~~~
// was: impl Add for &Inches {
impl Add for &'b Inches {
...
}
Compilation error:
error: use of undeclared lifetime name `'b` [E0261]
impl Add for &'b Inches {
impl
(now it compiles)(Rust playground link)
// was: impl Add for &'b Inches {
impl<'b> Add for &'b Inches {
...
}
This, finally, compiles correctly.
Why is
&Inches
inimpl Add for &Inches
considered to lack a lifetime specifier? What problem is solved by telling the compiler that this Add method is for&Inches
with some unspecified non-static lifetime'b
, and then never referring to that lifetime anywhere else?
The reason is simple: it wasn't implemented until Rust 1.31.
Now, the initial example compiles, and you can write impl Add for &Inches
instead of impl<'b> Add for &'b Inches
. This is because 1.31.0 stabilized new lifetime elision rules.
If you look at the RFC for lifetime elision you can see that your use case should be covered:
impl Reader for BufReader { ... } // elided
impl<'a> Reader for BufReader<'a> { .. } // expanded
However, I tried in the playground and it doesn't work. The reason is that it's not implemented yet.
I grepped Rust's source code for such cases, but there are suprisingly few of them. I could only find this series of implementations for Add
on native types:
impl Add<u8> for u8
impl<'a> Add<u8> for &'a u8
impl<'a> Add<&'a u8> for u8
impl<'a, 'b> Add<&'a u8> for &'b u8
As you can see the lifetimes are all explicit here; no elision happens.
For your specific problem, I believe you'll have to stick with explicit lifetimes until the RFC implementation is done!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With