有没有一种方法可以暗示可能包含任何数字元素的元组的特征?

时间:2019-06-21 04:51:00

标签: rust

我有一个这样的特征:

trait Foo {
    fn do_somthing(self) -> Self;
}

我想为一个元组实现此特征,该元组可以具有实现该特征的任意数量的元素。

impl<T> Foo for (T, T) where T: Foo {
    fn do_somthing(self) -> Self {
        let (t0, t1) = self;
        (t0.do_somthing(), t1.do_somthing())
    }
}

impl<T> Foo for (T, T, T) where T: Foo {
    fn do_somthing(self) -> Self {
        let (t0, t1, t2) = self;
        (t0.do_somthing(), t1.do_somthing(), t2.do_somthing())
    }
}

...

2 个答案:

答案 0 :(得分:1)

不。 (除非您准备使用宏,否则请参见其他答案)

Rust中的音节具有固定的长度just like arrays。我不相信您可以表达“任何长度的元组”的概念。

换句话说,2个元素的元组与3个元素的元组是不同的复合类型。如果您坚持使用元组,则必须采用上面概述的解决方案。

使用收藏集吗? (例如为现有的别名加别名并在其上实现特征)?

答案 1 :(得分:1)

注意:我不确定您是否应该执行此操作,但是无论如何,这是一种方法。 (对我来说很客气,这可能是因为我不知道如何制作更好的宏。)

同质元组(T, T)

描述方式:

impl<T> Foo for (T, T) where T: Foo

在这里,整个元组必须是同质的(即(MyType, MyType2).do_something()由于单态化将起作用)。 这会引发一个标记,因为元组用于异构数据。

如果仅实现一个特质元组仍然是您想要的特征,我们可以通过the standard library does to implement traits for varied length tuples的方式来实现一个宏,并进行一些修改。 (单击src右侧的impl,查看其来源。)

macro_rules! replace_expr {
    ($_t:tt $sub:ty) => {$sub};
}

macro_rules! tuple_impls {
    ( $( $name:ident )+ ) => {
        impl<T: Foo> Foo for ($(replace_expr!(($name) T),)+)
        {
            fn do_something(self) -> Self {
                let ($($name,)+) = self;
                ($($name.do_something(),)+)
            }
        }
    };
}

tuple_impls! { A }
tuple_impls! { A B }
tuple_impls! { A B C }
tuple_impls! { A B C D }
tuple_impls! { A B C D E }
tuple_impls! { A B C D E F }
tuple_impls! { A B C D E F G }
tuple_impls! { A B C D E F G H }
tuple_impls! { A B C D E F G H I }
tuple_impls! { A B C D E F G H I J }
tuple_impls! { A B C D E F G H I J K }
tuple_impls! { A B C D E F G H I J K L }

Playground

异构元组(T1, T2)

如果您对(MyType, MyType2).do_something()的工作没问题(两个都实现了Foo特性),则可以尝试以下更简单的宏:

macro_rules! tuple_impls {
    ( $( $name:ident )+ ) => {
        impl<$($name: Foo),+> Foo for ($($name,)+)
        {
            fn do_something(self) -> Self {
                let ($($name,)+) = self;
                ($($name.do_something(),)+)
            }
        }
    };
}

tuple_impls! { A }
tuple_impls! { A B }
tuple_impls! { A B C }
tuple_impls! { A B C D }
tuple_impls! { A B C D E }
tuple_impls! { A B C D E F }
tuple_impls! { A B C D E F G }
tuple_impls! { A B C D E F G H }
tuple_impls! { A B C D E F G H I }
tuple_impls! { A B C D E F G H I J }
tuple_impls! { A B C D E F G H I J K }
tuple_impls! { A B C D E F G H I J K L }

Playground