I want to check whether a type implements a trait without creating an object. But it doesn't compile. See the comments in code . So what should I do to get my goal?
#![feature(specialization)]
struct T1;
struct T2;
trait A {}
impl A for T1 {}
trait Get_Static<TraitType> {
fn has_trait() -> bool ;
}
default impl<TraitType, T> Get_Static<TraitType> for T
{
fn has_trait() -> bool { false }
}
impl<TraitType, T> Get_Static<TraitType> for T where T:TraitType
{
fn has_trait() -> bool { true }
}//Compiler complains TraitType is not a trait but type parameter
fn main() {
if <T1 as Get_Static>::<A>::has_trait() {println!("{}", true)} else {println!("{}", false)}
if <T2 as Get_Static>::<A>::has_trait() {println!("{}", true)} else {println!("{}", false)}
//This is surely wrong syntax but I don't know the right syntax
}
Warning: this solution no longer works with recent nightly (2022-01), and it is unknown when it stopped working.
Thanks to Stefan who smoothed out the last wrinkle.
<T2 as Get_Static>::<A>::has_trait()
//This is surely wrong syntax but I don't know the right syntax
This attempts to call:
The syntax is <Type as Trait>::associated_function()
. In this case, Type
is T1
, Trait
is Get_Static<A>
so this should be:
<T2 as Get_Static<A>>::has_trait()
impl<TraitType, T> Get_Static<TraitType> for T where T:TraitType { fn has_trait() -> bool { true } } //Compiler complains TraitType is not a trait but type parameter
It is not possible, directly, to indicate that TraitType
should be a trait
, however the Unsize
marker can be used to check if T: Unsize<TraitType>
which is sufficient for our purpose.
This requires 3 changes:
#![feature(unsize)]
as the Unsize
marker is unstable,Get_Static
generic parameter to be ?Sized
, because traits are unsized,T: Unsize<TraitType>
as constraint in the implementation.All told, this means:
#![feature(specialization)]
#![feature(unsize)]
trait GetStatic<TraitType: ?Sized> {
fn has_trait() -> bool ;
}
default impl<TraitType: ?Sized, T> GetStatic<TraitType> for T {
fn has_trait() -> bool { false }
}
impl<TraitType: ?Sized, T> GetStatic<TraitType> for T
where
T: std::marker::Unsize<TraitType>
{
fn has_trait() -> bool { true }
}
Which is then used as:
struct T1;
struct T2;
trait A {}
impl A for T1 {}
fn main() {
println!("{}", <T1 as GetStatic<A>>::has_trait());
println!("{}", <T2 as GetStatic<A>>::has_trait());
}