Rust traits:边界可能没有实现,我实现的 traits 不存在

Rust traits: The bounds might not be implemented, and the traits I've implemented does not exist

所以我一直在尝试为向量和矩阵数学实现一个库,并且我创建了一些可以正常工作但想泛化所有数字基元并将功能添加到普通运算符中的函数。

我的想法是为 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,
        }
    }
}

编译问题的一部分我认为为 "recursive" 结构实现特征是不正确的 像 Mat<Mat<T>>,如果你认为 Xtype X = Mat<T> 那么 Mat<T> 的 impl 就足够了:

impl<'a, T> Add for &'a Mat<T>
where
    T: PartialEq + PartialOrd + Add<T> + Clone

Mat<T> 值的附加实现:

impl<T> Add for Mat<T>
where
    T: PartialEq + PartialOrd + Add<T> + Clone

下面我 post 一个完整的工作代码,请注意 Output 类型不再是 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);
}

PS:你的Mat<T>类型不是经典意义上的矩阵,也许换个名字更合适,以免混淆。