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

Hen*_*ler 7 rust

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

struct Foo<T: u16 or u32 or u64> { ... }
Run Code Online (Sandbox Code Playgroud)

有没有办法表达这个?

Luk*_*oid 9

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

但是,要做到你是什么,你可以创建后的新特点,实现该特性的u16,u32并且u64,然后限制吨至您的新特点.

pub trait MyNewTrait {}

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

struct Foo<T: MyNewTrait> { ... }
Run Code Online (Sandbox Code Playgroud)

然后,您还可以添加方法上MyNewTraitimpls到封装特定的逻辑u16,u32u64.

  • @HenningKoehler:你可以,你只需要在特质级别声明它.那就是`pub trait MyNewTrait:添加<输出=自我> + Mul <输出=自我> + ... {} (3认同)
  • @HenningKoehler您可以在“Into&lt;usize&gt;”的结构或特征上添加另一个特征限制。`T: MyNewTrait + Into&lt;usize&gt;` 或 `trait MyNewTrait : Into&lt;usize&gt;` (3认同)
  • 是的,但这不允许我做我能用 u16、u32 或 u64 做的所有事情 - 例如,我无法使用值来检索数组的元素、比较两个值等。 (2认同)

tre*_*tcl 9

有时您可能想要使用具有enumtrait bound的而不是泛型类型。例如:

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

struct Foo { x: Unsigned, ... };
Run Code Online (Sandbox Code Playgroud)

与为现有类型实现新特征相比,创建新类型的一个优点是您可以向新类型添加外部特征和固有行为。你可以实现你喜欢的任何特性Unsigned,比如AddMul等等。当Foo包含一个时Unsigned,实现特性Unsigned不会影响Foo像将它们添加为Foo参数的边界(例如Foo<T: Add<Output=Self> + PartialCmp + ...>)的签名。另一方面,您仍然必须实现每个特征。

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


“性能原因”有点模棱两可,但是如果您正在考虑存储很多Unsigned都是相同内部类型的s,那么:

struct Foo([Unsigned; 1_000_000]);
Run Code Online (Sandbox Code Playgroud)

存储一百万u16秒会浪费大量空间,您仍然可以制作Foo泛型!只需实现From<u16>, From<u32>, 和From<u64>forUnsigned并改为写这个:

struct Foo<T: Into<Unsigned>>([T; 1_000_000]);
Run Code Online (Sandbox Code Playgroud)

现在您只有一个简单的 trait 绑定在 上T,您不会浪费标签和填充空间,并且处理的函数T总是可以将其转换Unsigned为进行计算。甚至可以完全优化转换成本。

也可以看看

  • 只是补充一下,“num”板条箱已经为您完成了这项工作:https://docs.rs/num/latest/num/traits/trait.Unsigned.html (2认同)