使用泛型进行算术运算时,不能应用二进制运算

时间:2015-12-08 16:38:41

标签: generics rust

我正在尝试使用num crate Float trait在我的库中实现泛型,但我遇到了与编译器对抗的问题。这有效:

impl Metric<f32> for Vector<f32> {
    fn norm(&self) -> f32 {
        let mut s = 0.0;

        for u in &self.data {
            s = s + u*u;
        }

        s.sqrt()
    }
}

但这不是:

impl<T: Float> Metric<T> for Vector<T> {
    fn norm(&self) -> T {
        let mut s = T::zero();

        for u in &self.data {
            s = s + u*u;
        }

        s.sqrt()
    }
}

后者给了我以下错误:

  

错误:二进制操作*无法应用于&T

类型

如果我删除引用并反复遍历self.data - 我得到一个借用的脱离上下文错误。

另一方面。我真的希望能够使用s +=代替s = s +。使用泛型可以阻止这一点 - 但这本身可能是另一个话题。

1 个答案:

答案 0 :(得分:4)

让我们仔细看看Float特质。它被定义为:

pub trait Float: Num + Copy + NumCast + PartialOrd + Neg<Output=Self> {
    // ...
}

潜入Num特质,我们看到:

pub trait Num: PartialEq + Zero + One +
               Add<Output=Self> + Sub<Output=Self> +
               Mul<Output=Self> + Div<Output=Self> + Rem<Output=Self>
{
    // ...
}

这意味着任何实现Float的类型都可以乘以其自己的类型。现在让我们回到你的代码。您正在迭代Vec<T>,为每个项目提供引用&T

所以你有一个&T并试图将其乘以另一个&T。这是一个简单的例子:

fn do_a_thing<T>(a: &T, b: &T)
    where T: Float
{
    let z = a * b;
}

这会产生同样的错误:binary operation `*` cannot be applied to type `&T`

问题是,您知道您可以将T乘以另一个T。要说,你必须明确地取消引用变量:

let z = (*a) * (*b);

对原始代码应用相同的更改会使其起作用。