The following rust program is valid, which surprises me since lifetime 'i is unconstrained, and I'm wondering what does it mean to add lifetime 'i to trait A even if the lifetime is not used.
trait A<'i> {}
struct B;
impl<'i> A<'i> for B {}
I came across this example by creating this code which compiles
struct Ref<'i> {
_txt: &'i str,
}
struct Object;
trait Trait<'i> {
type I;
fn foo(&self, input: &Self::I);
}
impl<'i> Trait<'i> for Object {
type I = Ref<'i>;
fn foo(&self, _input: &Ref<'i>) {}
}
However if I remove the lifetime from Trait it doesn't compile:
struct Ref<'i> {
_txt: &'i str,
}
struct Object;
trait Trait {
type I;
fn foo(&self, input: &Self::I);
}
impl<'i> Trait for Object {
type I = Ref<'i>;
fn foo(&self, _input: &Ref<'i>) {}
}
the type I may depend on the type Self and on the lifetime 'i.
Whereas in this trait
the type I may depend only on the type Self and nothing else.
This is why the implementation
is not allowed. I depends on more than just the type Object: If I asked you “what’s the type I in the implementation of Trait for Object”, the answer “it’s Ref<'i>” would be unsatisfactory, because I didn’t mention any lifetime called “'i”, and I’d rightfully ask “where does this lifetime come from?”
On the other hand
is fine: If I asked you “for any lifetime 'i, what’s the type I in the implementation of Trait<'i> for Object”, the answer “it’s Ref<'i>” would be satisfactory. The type uses a lifetime that I already know, I mentioned it in the question myself.
Oh, but now you could say “wait, you formulated the question differently; you mentioned a lifetime 'i in the question!” Well, let’s try. We will reconsider
and ask the question in the form “for any lifetime 'i, what’s the type I in the implementation of Trait for Object?”, with the answer “it’s Ref<'i>”. The problem here is that, imagine we have two (different) lifetime 'foo and 'bar, this answer would tell us that “the type I in the implementation of Trait for Object” is Ref<'foo>, but also by the same argument, we get that this type is Ref<'bar>. So Ref<'foo> and Ref<'bar> are the same type!? But they aren’t, we chose two different lifetimes. That’s essentially the rationale why “unconstrained lifetime parameters” are forbidden. If they were allowed, we could abuse the type system to convince the compiler that two distinct types are the same even though they shouldn’t be.