我有一个名为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
答案 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
特征。