matrix - Rust 特征 : The bounds might not be implemented, 并且我实现的特征不存在

标签 matrix vector rust traits bounds

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

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

相关文章:

python - 如何以特定方式将一个小矩阵沿对角线添加到一个较大的矩阵中?

r - 使用 for 循环命名向量中的组件

rust - 如何在不使用类型说明的情况下创建盒装切片?

javascript - JavaScript 中的单色抖动 (Bayer, Atkinson, Floyd–Steinberg)

c# - 如何计算协方差矩阵

performance - Numpy Hermitian 矩阵类

C++:由整数键控的对象的映射或 vector ?

c++ - 如何实际上在C++中 “clear”一个 vector ?

rust - 如何在捕获时向panick_info添加更多上下文?

types - 什么时候需要使用类型注解?