所以我一直在尝试为向量和矩阵数学实现一个库,并且我创建了一些可以正常工作但希望对所有数字基元进行泛化并将功能添加到普通运算符中的函数。
我的想法是为 Vec<T>
创建一个容器, 可以包含数字类型(如 i32
)或 Vec
的另一个容器, 以便在可能的情况下使用矩阵。因此:
#[derive(Clone, Debug)]
struct Mat<T>(Vec<T>);
然后,为了将任意数量的两个 vec 相加,我实现了 Add as:
impl<'a, T> Add for &'a Mat<T>
where T: PartialEq + PartialOrd + Add<T> + Sub<T> + Mul<T> + Div<T> + Rem<T> + Clone {
type Output = Option<Mat<<T as std::ops::Add>::Output>>;
fn add(self, other: &Mat<T>) -> Self::Output {
let a: &Vec<T> = self.pop();
let b: &Vec<T> = other.pop();
match a.len() == b.len() {
true => {
let mut retvec: Vec<<T as std::ops::Add>::Output> = Vec::new();
for i in 0..a.len() {
retvec.push(a[i].clone() + b[i].clone());
}
Some(Mat(retvec))
},
false => None
}
}
}
编辑:为了进一步澄清,Mat::pop()
只是解包函数,虽然可能命名不当。
将任意数量的两个向量相加的基本场景似乎可行。
#[test]
fn add_override_vectors() {
let vec: Mat<i32> = Mat(vec![2, 2, 2]);
let newvec = &vec + &vec;
assert_eq!(*newvec.unwrap().pop(), vec![4,4,4]);
}
但是矩阵让我很头疼。对于他们来说,add 函数看起来非常相似,除了 let Some(x)
。声明:
impl<'a, T> Add for &'a Mat<Mat<T>>
where T: Add<&'a Mat<T>>{
type Output = Option<Mat<T>>;
fn add(self, other: &Mat<Mat<T>>) -> Self::Output {
let a: &Vec<Mat<T>> = self.pop();
let b: &Vec<Mat<T>> = other.pop();
match a.len() == b.len() {
true => {
let mut retvec: Vec<T> = Vec::new();
for i in 0..a.len() {
if let Some(x) = &a[i] + &b[i] {
retvec.push(x);
}
}
Some(Mat(retvec))
},
false => None
}
}
}
我得到的错误信息是:
error[E0369]: binary operation `+` cannot be applied to type `&Mat<T>`
--> src\main.rs:46:38
|
46 | if let Some(x) = &a[i] + &b[i] {
| ^^^^^^^^^^^^^
|
= note: an implementation of `std::ops::Add` might be missing for `&Mat<T>`
所以编译器说 Add
可能不会为 &Mat<T>
实现,但我认为我已经指定了界限,因此它在 where T: Add<&'a Mat<T>
中具有该要求.在我看来,&a[i]
中的内容似乎都是应该实现 Add 特性。我在这里做错了什么?
作为额外说明,我的想法是 Add for &'a Mat<Mat<T>>
应该能够递归调用直到它归结为 Vec
其中包含实际数字类型。然后 Add for &'a Mat<T>
应该被调用。
最佳答案
有两个问题:错误关联Output
类型和类型 retvec
类似的东西应该可以工作:
impl<'a, T> Add for &'a Mat<Mat<T>>
where
T: PartialEq + PartialOrd + Add<T> + Clone,
{
type Output = Option<Mat<Mat<<T as std::ops::Add>::Output>>>;
fn add(self, other: &Mat<Mat<T>>) -> Self::Output {
let a: &Vec<Mat<T>> = self.pop();
let b: &Vec<Mat<T>> = other.pop();
match a.len() == b.len() {
true => {
let mut retvec: Vec<Mat<<T as std::ops::Add>::Output>> = Vec::new();
for i in 0..a.len() {
if let Some(x) = &a[i] + &b[i] {
retvec.push(x);
}
}
Some(Mat(retvec))
}
false => None,
}
}
}
编译问题的一部分我认为为“递归”结构实现特征是不正确的
喜欢Mat<Mat<T>>
,如果你认为 X
作为type X = Mat<T>
然后是 Mat<T>
的含义足够了:
impl<'a, T> Add for &'a Mat<T>
where
T: PartialEq + PartialOrd + Add<T> + Clone
带有 Mat<T>
的附加实现值(value)观:
impl<T> Add for Mat<T>
where
T: PartialEq + PartialOrd + Add<T> + Clone
下面我发布了完整的工作代码,请注意 Output
type 不再是 Option<Mat<T>>
但是一个普通的Mat<T>
目的:
这避免了很多令人头疼的问题,而且如果您想隐含某种类型的代数,这在概念上可能是错误的。
use std::ops::*;
use std::vec::Vec;
#[derive(Clone, Debug, PartialEq, PartialOrd)]
struct Mat<T>(Vec<T>);
impl<T> Mat<T> {
fn pop(&self) -> &Vec<T> {
&self.0
}
}
impl<T> Add for Mat<T>
where
T: PartialEq + PartialOrd + Add<T> + Clone,
{
type Output = Mat<<T as std::ops::Add>::Output>;
fn add(self, other: Mat<T>) -> Self::Output {
let a: &Vec<T> = self.pop();
let b: &Vec<T> = other.pop();
match a.len() == b.len() {
true => {
let mut retvec: Vec<<T as std::ops::Add>::Output> = Vec::new();
for i in 0..a.len() {
retvec.push(a[i].clone() + b[i].clone());
}
Mat(retvec)
}
false => Mat(Vec::new()),
}
}
}
impl<'a, T> Add for &'a Mat<T>
where
T: PartialEq + PartialOrd + Add<T> + Clone,
{
type Output = Mat<<T as std::ops::Add>::Output>;
fn add(self, other: &Mat<T>) -> Self::Output {
let a: &Vec<T> = self.pop();
let b: &Vec<T> = other.pop();
match a.len() == b.len() {
true => {
let mut retvec: Vec<<T as std::ops::Add>::Output> = Vec::new();
for i in 0..a.len() {
retvec.push(a[i].clone() + b[i].clone());
}
Mat(retvec)
}
false => Mat(Vec::new()),
}
}
}
#[test]
fn add_override_vectors() {
let vec: Mat<Mat<i32>> = Mat(vec![Mat(vec![2, 2, 2]), Mat(vec![3, 3, 3])]);
let newvec = &vec + &vec;
assert_eq!(*newvec.pop(), vec![Mat(vec![4, 4, 4]), Mat(vec![6, 6, 6])]);
}
#[test]
fn add_wrong_vectors() {
let vec1: Mat<Mat<i32>> = Mat(vec![Mat(vec![2, 2, 2]), Mat(vec![4, 4, 4])]);
let vec2: Mat<Mat<i32>> = Mat(vec![Mat(vec![3, 3, 3]), Mat(vec![3, 3])]);
let newvec = &vec1 + &vec2;
assert_eq!(*newvec.pop(), vec![Mat(vec![5, 5, 5]), Mat(vec![])]);
}
fn main() {
let vec: Mat<Mat<i32>> = Mat(vec![Mat(vec![1, 2, 2]), Mat(vec![3, 3, 3])]);
let newvec = &vec + &vec;
println!("Hello, world!: {:?}", newvec);
}
附言:你的Mat<T>
type 不是经典意义上的矩阵,也许另一个名称应该更合适以避免混淆。
关于matrix - Rust 特征 : The bounds might not be implemented, 并且我实现的特征不存在,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52163383/