有没有办法递归地压扁元组?

时间:2016-10-21 13:56:48

标签: rust tuples generic-programming

在Rust中,有没有办法使用traitimpl来(递归地)展平元组?

如果它有用,那么适用于N个嵌套对的东西是一个好的开始

trait FlattenTuple {
    fn into_flattened(self) -> /* ??? */
}

// such that
assert_eq!((1, (2, 3)).into_flattened(), (1, 2, 3))

如果可以使用任何类型的嵌套元组进行扩展,那将会更好:

assert_eq!(((1, 2), 2, (3, (4, 5))).into_flattened(), (1, 2, 2, 3, 4, 5))

2 个答案:

答案 0 :(得分:3)

也许对于某些小的定义" flatten",但实际上不是真的。

从最具体的实施开始:

trait FlattenTuple {
    fn into_flattened(self) -> (u8, u8, u8);
}

impl FlattenTuple for (u8, (u8, u8)) {
    fn into_flattened(self) -> (u8, u8, u8) {
        (self.0, (self.1).0, (self.1).1)
    }
}

然后使它更通用:

trait FlattenTuple {
    type Output;
    fn into_flattened(self) -> Self::Output;
}

impl<A, B, C> FlattenTuple for (A, (B, C)) {
    type Output = (A, B, C);

    fn into_flattened(self) -> Self::Output {
        (self.0, (self.1).0, (self.1).1)
    }
}

然后重复每个可能的排列

impl<A, B, C, D, E, F> FlattenTuple for ((A, B), C, (D, (E, F))) {
    type Output = (A, B, C, D, E, F);

    fn into_flattened(self) -> Self::Output {
        ((self.0).0, (self.0).1, self.1, (self.2).0, ((self.2).1).0, ((self.2).1).1)
    }
}

这两个实现涵盖了你的两个案例。

但是,您必须通过代码生成枚举您喜欢的每种输入类型。我无法意识到&#34;检查&#34;输入类型然后&#34;拼接&#34;它进入输出类型。

你甚至可以尝试写一些有点递归的东西:

impl<A, B, C, D, E, F> FlattenTuple for (A, B)
    where A: FlattenTuple<Output = (C, D)>,
          B: FlattenTuple<Output = (E, F)>,
{
    type Output = (C, D, E, F);

    fn into_flattened(self) -> Self::Output {
        let (a, b) = self;
        let (c, d) = a.into_flattened();
        let (e, f) = b.into_flattened();

        (c, d, e, f)
    }
}

但这会很快遇到基本情况问题:终端42没有实现FlattenTuple,如果你尝试impl<T> FlattenTuple for T,你会遇到冲突的特征实施。

答案 1 :(得分:0)

我用专业化和自动特征实现了这一点。

docs.rs

github repo

用法基本上是

assert_eq!((1, (2, ((3,) (4, 5)), (), 6).flatten(), (1, 2, 3, 4, 5, 6));

它删除所有空单位元组()(如python)。

如果您正在编写通用代码,则需要添加

where (A, B): Flatten

rustc想要这个,因为只有当输出元组的长度小于13时才实现Flatten。