如何需要一个泛型类型实现诸如ADD,SUB,MUL还是Div在通用功能的操作?如何需要一个泛型类型实

2019-05-10 11:54发布

我试图实现防锈的通用功能,其中的参数的唯一要求是乘法运算应该被定义。 我想实现一个通用的“权力”,但将与一个简单的去cube功能来说明这个问题:

use std::ops::Mul;

fn cube<T: Mul>(x: T) -> T {
    x * x * x
}

fn main() {
    println!("5^3 = {}", cube(5));
}

编译当我得到这个错误:

error[E0369]: binary operation `*` cannot be applied to type `<T as std::ops::Mul>::Output`
 --> src/main.rs:4:5
  |
4 |     x * x * x
  |     ^^^^^^^^^
  |
  = note: an implementation of `std::ops::Mul` might be missing for `<T as std::ops::Mul>::Output`

这是什么意思? 难道我选择了错误的特质? 我怎样才能解决这个问题?

Answer 1:

让我们打破你的榜样了一下:

fn cube<T: Mul>(x: T) -> T {
    let a = x * x;
    let b = a * x;
    b
}

哪些类型的ab ? 在这种情况下,类型a<T as std::ops::Mul>::Output -声音从错误信息熟悉的? 然后,我们正在努力增加那种类型的x一遍,但没有保证Output能够被任何东西所乘以!

让我们做最简单的事情,并说, T * T需要导致T

fn cube<T: Mul<Output = T>>(x: T) -> T {
    x * x * x
}

不幸的是,这给出了两个类似的错误:

error[E0382]: use of moved value: `x`
 --> src/lib.rs:6:9
  |
6 |     x * x * x
  |     -   ^ value used here after move
  |     |
  |     value moved here
  |
  = note: move occurs because `x` has type `T`, which does not implement the `Copy` trait

这是因为Mul性状按值接受参数 ,所以我们增加了Copy ,所以我们可以复制的价值。

我也切换到where条款,因为我更好喜欢它,它是笨重有那么多在线:

fn cube<T>(x: T) -> T
where
    T: Mul<Output = T> + Copy
{
    x * x * x
}

也可以看看:

  • 如何落实到一个结构的引用添加特质?
  • 如何写开往添加泛型类型的两个引用一个特点?


Answer 2:

结合的T: Mul并不意味着二进制操作的结果是类型的也T 。 结果类型是这样的性状的关联类型Output

的另一个问题是,锈病1.0之前操作切换性状从通按引用传递按值。 在通用代码这可有点在一个痛苦的对接的(至少目前),因为这些运营商消耗它们的操作数,除非你还需要类型为Copy

只是为了完整性(如果你不喜欢,要求Copy ),让我补充有关可能的替代方向的一些信息。

对于通用代码的缘故,鼓励“数字类型”的作者提供这些运营商的性状附加的非消费实现,这样就不需要CopyClone 。 例如,标准库已经提供了以下实施方案:

 f64 implements Mul< f64>
 f64 implements Mul<&f64>
&f64 implements Mul< f64>
&f64 implements Mul<&f64>

每个这些实现的具有f64作为Output类型。 利用直接这些特性并不漂亮:

fn cube<T>(x: &T) -> T
where
    for<'a> T: Mul<&'a T, Output = T>,
    for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
    x * x * x
}

最后,我们可能会得到一些(略)更高层次的特点,这将减少噪音。 例如: T: Mul2可能意味着T: Mul<T> + Mul<&T>&T: Mul<T> + Mul<&T>但在写这篇的时候,锈编译器似乎并不能够处理该。 至少我无法成功编译下面的代码:

use std::ops::Mul;

pub trait Mul2
where
    Self: Mul<Self, Output = Self>,
    Self: for<'a> Mul<&'a Self, Output = Self>,
    for<'a> &'a Self: Mul<Self, Output = Self>,
    for<'a, 'b> &'a Self: Mul<&'b Self, Output = Self>,
{
}

impl<T> Mul2 for T
where
    T: Mul<T, Output = T>,
    T: for<'a> Mul<&'a T, Output = T>,
    for<'a> &'a T: Mul<T, Output = T>,
    for<'a, 'b> &'a T: Mul<&'b T, Output = T>,
{
}

fn cube<T: Mul2>(x: &T) -> T {
    x * x * x
}

fn main() {
    let c = cube(&2.3);
    println!("Hello, world! {}", c)
}

我认为这是肯定地说,事情会在这方面有所改善。 现在,一般地实现锈数字算法的能力不如我想的那样。



文章来源: How do I require a generic type implement an operation like Add, Sub, Mul, or Div in a generic function?
标签: generics rust