Module higher_kinded_types::type_eq
source · advanced
only.Expand description
Niche and advanced, you can ignore this to begin with. Module for type-equality hacks.
In certain scenarios, you may have a T : ForLt
in scope which you want to
constrain to match some specific type when fed some specific lifetime;
e.g.
//! pseudo-code
<'r, T : ForLt>
where
T::Of<'r> = &'r str
In that case, you can actually just write the corresponding real code:
fn f<'s, T : ForLt>(s: &'s str)
where
T : ForLt<Of<'s> = &'s str>,
{
let _: T::Of<'s> = s;
}
which does work 🙂.
It even works with higher-order lifetimes!
fn f<T : ForLt>(s: String)
where
T : for<'local> ForLt<Of<'local> = &'local str>,
{
let _local: T::Of<'_> = &s;
}
But in other more contrived situations, potentially outside of HKTs altogether, these type equality bounds may be unusable or buggy.
In that case, the workaround is to replace type equality constraints, with good old trait bounds, but with a trait designed so as to nonetheless signify type equality:
Hence the trait Is
. Alas, it does come with some caveats, since when
T : Is<EqTo = U>,
Rust will nonetheless still be treating T
and U
as distinct types.
Which is why this module provides helper cast_right()
and cast_left()
functions:
use ::higher_kinded_types::{ForLt, type_eq::{self, Is}};
fn f<'a, T : ForLt>(a: &'a str)
where
T::Of<'a> : Is<EqTo = &'a str>,
{
let _: T::Of<'a> = type_eq::cast_left::<T::Of<'a>>(a);
}
But perhaps more interestingly, cast_right()
and cast_left()
are
unable to handle types depending on T
, such as Vec<T>
vs. Vec<U>
.
That’s when we’d like to use “generic-over-a-type generics”, that is, type GATs!
…ish: while they’re not fully supported (no ergonomic instantiation), it can
be intellectually interesting to notice that once we let go of ergonomics,
there can be actual usages of type “HKTs” GATs.
See, for instance, cast_wrapper_right
and its documentation example.