我有一个名为 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
的版本使用-
, %
, *
, /
而不是 +
,并为每个操作实现各自的特征听起来像是一件苦差事。我只对有符号整数和 float 感兴趣,所以这些 num 子类型可能存在一个特征?
我的 Cargo.toml
为了方便起见:
[package]
name = "minimal_example_2"
version = "0.1.0"
authors = ["User"]
[dependencies]
num = "0.1.36"
最佳答案
要认识到的重要一点是代码并没有试图添加两个 N
;该代码试图添加两个 对 N
的引用 ( &N
)。看报错信息(重点加了):
binary operation
+
cannot be applied to type&N
通过使用 iter
,您正在对向量中的值进行引用迭代。无法保证对实现特征的类型的引用实现了特征。
- When should I not implement a trait for references to implementors of that trait?
- How do I implement the Add trait for a reference to a struct?
此外,T: Add<T, Output=T>
不暗示&T: Add<&T, Output=T>
.
but I do not understand why I need to implement the
Add
trait. As if there are numbers that cannot be added...
你为什么认为 N
是一个数字? Rust 中存在的任何可能类型 都欢迎实现任何特征,包括 Num
.如果有意义,您可以实现 Num
适合您自己的类型。
perhaps there exists a trait for these subtypes of num?
同样,一旦存在特征,任何类型都欢迎实现它。
对于它的值(value),我会像这样实现它:
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
可以应用特征。
关于generics - 为什么需要实现 Add 来添加两个具有特征 Num 的变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40241159/