How to combine multiple traits as a "trait tuple"?

Viewed 170

I write a lib like:

struct Foo<A: AppleTrait, B: BananaTrait, C: CarrotTrait> {...}

impl<A: AppleTrait, B: BananaTrait, C: CarrotTrait> Foo<A,B,C> {...}

struct Bar<A: AppleTrait, B: BananaTrait, C: CarrotTrait> {...}

impl<A: AppleTrait, B: BananaTrait, C: CarrotTrait> Bar<A,B,C> {...}

... and many more...

Notice that, things like <A: AppleTrait, B: BananaTrait, C: CarrotTrait> always come together, and has appeared many many times. So I want to eliminate such a burden.

Thus I hope I can do something like:

define_the_trait_alias ABCTrait = (A: AppleTrait, B: BananaTrait, C: CarrotTrait); // How to do this?

struct Foo<ABC: ABCTrait> {...}

impl<ABC: ABCTrait> Foo<ABC> {...}

Thanks!

2 Answers

Perhaps you can use associated types rather than generics. For example:

trait AbcTrait {
    type Apple: AppleTrait;
    type Banana: BananaTrait;
    type Carrot: CarrotTrait;
}

struct Foo<Abc: AbcTrait> {
    abc: Abc,
}
impl<Abc: AbcTrait> Foo<Abc> {}

struct Bar<Abc: AbcTrait> {
    abc: Abc,
}
impl<Abc: AbcTrait> Bar<Abc> {}

When defining a concrete implementation of the trait, you get to choose which concrete type implements which associated type requested by the trait:

impl AbcTrait for Salad {
    type Apple = GrannySmith;
    type Banana = Cavendish;
    type Carrot = LunarWhite;
}

You can make a super-trait that takes A, B, and C as associated types. Then you implement that trait for (A,B,C) and use that whenever you need to specify types, e.g., some_func_that_takes_type_params::<(StructA, StructB, StructC)>(). To access A, B, or C, you use the associated types instead:

trait SuperTrait{
    type A: AppleTrait;
    type B: BananaTrait;
    type C: CarrotTrait;
}
impl<A: AppleTrait, B: BananaTrait, C: CarrotTrait> SuperTrait for (A,B,C)
{
    type A = A;
    type B = B;
    type C = C;
}

struct Foo<D: SuperTrait> (std::marker::PhantomData<D>);

impl<D: SuperTrait> Foo<D> {
    /// Example function that returns an A
    fn return_a(&self) -> D::A{
        todo!()
    }
}
Related