Exercise: implement Invokable<&'static Value>
for i32
and see if you can figure out why you can't implement Visitor for i32
analogously to your generic implementation.
And/or try it with impl<'a> Invokable<&'a Value> for &'a str
.
You can think of
impl<'a, F> Visitor for F
where
F: Invokable<&'a Value> + 'a,
as "there exists a lifetime 'a
and a type F
such that F: Invokable<&'a Value>
". Or roughly, "F
has a method invoke
that takes &'s Self
for all lifetimes 's
, and &'a Value
(for the specific lifetime 'a
that we said exists)."
But if you look at the trait you're trying to implement:
trait Visitor {
fn emit(&self, value: &Value);
}
This says, "to implement Visitor
, define a function emit
that takes &'s Self
and &'v Value
for all lifetimes 's
and 'v
".
So here's the mismatch:
// vvvvvvvvvv
Exists<'a> ForAll<'s> fn(&'s Self, &'a Value) // what F::invoke does
ForAll<'v> ForAll<'s> fn(&'s Self, &'v Value) // what F::emit needs
Since F::emit
has to handle any input lifetime on the &'v Value
, you need F
to implement Invoke<&'v Value>
for all 'v
, not just one specific 'a
, and that's what the for<'a>
bound does: effectively changes the Exists<'a>
to a ForAll<'a>
.
impl<F> Visitor for F
where
F: for<'a> Invokable<&'a Value>,
The technical name for such a bound is a higher-ranked trait bound, or HRTB.
Nit: there is no inference here, it's just straight-up syntactical sugar.
AFAIK it's only mentioned in the reference in passing here.
lifetime arguments can be elided in function item, function pointer, and closure trait signatures.
Which I would agree isn't adequate to explain the higher-ranked connection (and fails to mention dyn [closure trait]
types).