Is it possible to automatically implement a trait

2020-02-15 06:44发布

Suppose that I have a

trait Happy {}

I can implement Happy for whatever struct I might want, for example:

struct Dog;
struct Cat;
struct Alligator;

impl Happy for Dog {}
impl Happy for Cat {}
impl Happy for Alligator {}

Now, I would like to automatically impl my Happy trait for whatever tuple is made up of types that all implement the Happy trait. Intuitively, a tuple of all happy is happy as well.

Is it possible to do such a thing? For example, I can trivially extend the implementation of Happy to whatever tuple of two Happy types:

impl <T, Q> Happy for (T, Q) where T: Happy, Q: Happy {}

As a result, this compiles perfectly:

fn f(_: impl Happy) {
}

fn main() {
    f((Dog{}, Alligator{}));
}

But how could I generalize that to any tuple, of any length? As far as my understanding goes, we don't have variadic generics in Rust. Is there a workaround?

1条回答
迷人小祖宗
2楼-- · 2020-02-15 07:01

we don't have variadic generics in Rust.

Correct.

Is there a workaround?

You use a macro:

trait Happy {}

macro_rules! tuple_impls {
    ( $head:ident, $( $tail:ident, )* ) => {
        impl<$head, $( $tail ),*> Happy for ($head, $( $tail ),*)
        where
            $head: Happy,
            $( $tail: Happy ),*
        {
            // interesting delegation here, as needed
        }

        tuple_impls!($( $tail, )*);
    };

    () => {};
}

tuple_impls!(A, B, C, D, E, F, G, H, I, J,);

This now compiles:

fn example<T: Happy>() {}

fn call<A: Happy, B: Happy>() {
    example::<(A, B)>();
} 

This isn't generally seen as a big problem because long tuples are basically unreadable and you can always nest tuples if really needed.

See also:

查看更多
登录 后发表回答