I'm working with a trait which cannot be touched like this(minimized):
// The associated version
trait Testable {
type T;
fn test_it(&self, x: Self::T) -> bool;
}
Then I try to impl it with, say, i32:
impl Testable for i32 {
type T = &str;
fn test_it(&self, x: Self::T) -> bool {
x.is_empty()
}
}
However, I got compiler error:
type T = &str;
^ explicit lifetime name needed here
The associated type Self::T is just on the input parameter of method test_it. Why does the compiler claim that I have to provide lifetime annotation?
Note that if I change T to generic type like:
// The generic version
trait Testable<T> {
fn test_it(&self, x: T) -> bool;
}
impl Testable<&str> for i32 {
fn test_it(&self, x: &str) -> bool {
x.is_empty()
}
}
This time the code compiled without error.
The problem is
(1) why I have to provide lifetime annotation in the associated version since the type only appears at the input parameter side?
(2) Why the generic version compiled? Are there any deep differences between the two versions?
The difference is that the associated type is chosen by the trait, whereas the generic parameter is chosen by the caller. So with this code:
impl Testable for i32 {
type T = &str;
fn test_it(&self, x: Self::T) -> bool {
x.is_empty()
}
}
The compiler needs to be able to know everything about T without looking at any other part of the code. But it can't: there is no way to know the lifetime of the reference just by looking at this code (btw the only lifetime that can work here is 'static).
On the other hand with this code:
impl Testable<&str> for i32 {
fn test_it(&self, x: &str) -> bool {
x.is_empty()
}
}
&str is an incomplete type since it's missing the lifetime, but that's ok because the type will be filled-in on the call site (like all template parameters).
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