有没有办法将泛型类型限制为几种类型之一?

时间:2016-11-23 23:47:59

标签: rust

我正在尝试创建一个泛型结构,它使用“整数类型”来引用数组。出于性能原因,我希望能够轻松指定是使用u16u32还是u64。像这样的东西(显然是无效的Rust代码):

struct Foo<T: u16 or u32 or u64> { ... }

有没有办法表达这个?

2 个答案:

答案 0 :(得分:9)

对于数组的引用,通常只使用usize而不是不同的整数类型。

但是,要在创建新特征后执行操作,请为u16u32u64实施该特征,然后将T限制为新的特征。

pub trait MyNewTrait {}

impl MyNewTrait for u16 {}
impl MyNewTrait for u32 {}
impl MyNewTrait for u64 {}

struct Foo<T: MyNewTrait> { ... }

然后,您还可以在MyNewTraitimpl上添加方法,以封装特定于u16u32u64的逻辑。

答案 1 :(得分:3)

有时您可能想使用enum而不是带有特征绑定的泛型类型。例如:

enum Unsigned {
    U16(u16),
    U32(u32),
    U64(u64),
}

struct Foo { x: Unsigned, ... };

与为现有类型实现新特征相比,使新类型具有一个优点是您可以向新类型添加外来特征和固有行为。您可以实现Unsigned所需的任何特征,例如AddMul等,甚至是SliceIndex<[T]>,以便可以将其用于索引切片。当Foo包含Unsigned时,在Unsigned上实现特征不会影响Foo的签名,就像将它们添加为Foo的边界一样参数(例如Foo<T: Add<Output=Self> + PartialCmp + ...>)。另一方面,您仍然必须实现每个特征。

要注意的另一件事:虽然通常可以总是创建一个新类型并为其实现特征,但是枚举是“封闭的”:您不能在不触及其他所有Unsigned的情况下为其添加新类型。实现,就像使用特质一样。取决于您的设计要求,这可能是好事还是坏事。


“性能原因”有点模棱两可,但是如果您想存储很多Unsigned,它们将都是相同的内部类型,并且:

struct Foo([Unsigned; 1_000_000]);

存储一百万个u16会浪费大量空间,您仍然可以使Foo通用!只需为From<u16>实现From<u32>From<u64>Unsigned并将其编写为:

struct Foo<T: Into<Unsigned>>([T; 1_000_000]);

现在,您在T上只有一个简单的特征,您没有浪费标签和填充的空间,处理T的函数可以始终将其转换为Unsigned做计算。转换成本甚至可以完全被优化。

另请参见