炸鱼薯条德里克
炸鱼薯条德里克

Reputation: 1009

How to check whether a generic type implements a generic trait?

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
}

Upvotes: 3

Views: 4627

Answers (1)

Matthieu M.
Matthieu M.

Reputation: 300439

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:

  • a trait associated function,
  • implemented for a particular type.

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:

  • enabling the nightly feature #![feature(unsize)] as the Unsize marker is unstable,
  • allowing the Get_Static generic parameter to be ?Sized, because traits are unsized,
  • using 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());
}

See it in action on the playground

Upvotes: 1

Related Questions