为什么需要实现Add以使用特征Num添加两个变量?

时间:2016-10-25 13:22:04

标签: generics rust

我有一个名为add_vec的函数。它需要两个向量并创建一个新向量,方法是对压缩向量中的元素对执行元素加法。

extern crate num;
use num::traits::Num;

fn add_vec<N: Num>(v1s: Vec<N>, v2s: Vec<N>) -> Vec<N> {
    let mut v3s = Vec::new();
    for (v1, v2) in v1s.iter().zip(v2s.iter()) {
        v3s.push(v1 + v2)
    }
    v3s
}

#[cfg(test)]
mod tests {
    use super::add_vec;
    #[test]
    fn it_works() {
        let v1s = vec![1, 0, 3];
        let v2s = vec![0, 1, 1];
        let v3s = add_vec(v1s, v2s);
        assert_eq!(v3s, vec![1, 1, 4]);
    }
}

问题是我最终得到以下错误消息:

error[E0369]: binary operation `+` cannot be applied to type `&N`
  --> src/lib.rs:14:18
   |
14 |         v3s.push(v1 + v2)
   |                  ^^
   |
note: an implementation of `std::ops::Add` might be missing for `&N`
  --> src/lib.rs:14:18
   |
14 |         v3s.push(v1 + v2)
   |                  ^^

我知道Requiring implementation of Mul in generic function已经回答了这个问题,但我不明白为什么我需要实现Add特征。好像有些数字无法添加......

有没有办法在不实施Add的情况下解决这个问题?我想创建一个使用add_vec-%*代替/的{​​{1}}版本,并实现相应的特征对于每个操作听起来像一个苦差事。我只对有符号的整数和浮点数感兴趣,所以也许存在这些num的子类型的特征?

为方便起见我的+

Cargo.toml

1 个答案:

答案 0 :(得分:6)

要认识到的重要一点是代码并没有尝试添加两个N;代码正在尝试向N&N)添加两个引用。查看错误消息(强调添加):

  

二进制操作+无法应用键入&N

通过使用iter,您将迭代引用到向量内的值。不保证为实现特征的类型的引用实现了特征。

此外,T: Add<T, Output=T> 暗示&T: Add<&T, Output=T>

  

但我不明白为什么我需要实现Add特征。好像有些数字无法添加......

为什么您认为N 是一个数字欢迎使用Rust中存在的任何可能的类型来实现任何特征,其中包括Num。如果它有意义,您可以为自己的类型实现Num

  

或许存在这些num?

子类型的特征

同样,一旦存在某个特征,欢迎使用任何类型来实现它。

为了它的价值,我将这样实现:

use std::ops::Add;

fn add_vec<'a, N>(v1s: &'a [N], v2s: &'a [N]) -> Vec<N>
    where &'a N: Add<Output = N>
{
    v1s.iter().zip(v2s.iter()).map(|(v1, v2)| v1 + v2).collect()
}

请参阅Why is it discouraged to accept a reference to a String (&String) or Vec (&Vec) as a function argument?(我们也只是 需要来取得所有权)。使用map将更有效 - 它可以一次性预分配输出向量。

但是,如果你真的想要使用矢量:

fn add_vec<N: Num>(v1s: Vec<N>, v2s: Vec<N>) -> Vec<N> {
    v1s.into_iter()
        .zip(v2s.into_iter())
        .map(|(v1, v2)| v1 + v2)
        .collect()
}

请注意into_iter使用向量,产生值而不是引用。因此可以应用Num特征。