实现特征时类型不匹配

Mismatched types when implementing a trait

为了学习 Rust,我正在构建自己的 Matrix class。我对Add trait的实现如下:

impl<T: Add> Add for Matrix<T>
{
    type Output = Matrix<T>;

    fn add(self, _rhs: Matrix<T>) -> Matrix<T>
    {
        assert!(self.rows == _rhs.rows && self.cols == _rhs.cols,
                "attempting to add matrices of different sizes");

        let mut res: Matrix<T> = Matrix::<T>{
            rows: self.rows,
            cols: self.cols,
            data : Vec::<T>::with_capacity(self.rows * self.cols),
        };

        for i in 0..self.rows*self.cols{
            res.data.push(self.data[i] + _rhs.data[i]);
        }
        res
   }
}

但我收到以下错误

       Compiling matrix v0.1.0 (file://~/soft/rust/projects/matrix)
src/lib.rs:35:27: 35:54 error: mismatched types:
 expected `T`,
    found `<T as core::ops::Add>::Output`
(expected type parameter,
    found associated type) [E0308]
src/lib.rs:35             res.data.push(self.data[i] + _rhs.data[i]);
                                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~

根据错误报告,我想我需要在其他地方指出 T 实现了 Add 特征,但在我尝试这样做的任何地方,我要么得到相同的错误,要么得到解析错误。

顺便说下我对Matrix的定义是

pub struct Matrix<T> {
    pub rows: usize,
    pub cols: usize,
    pub data: Vec<T>,
}

使用 T: Add 作为界限表示可以写 T + T,但它不会对由此产生的类型施加任何限制,特别是,它可能不是 T。你依赖它 T 才能 return Matrix<T>.

一种方法是要求 T: Add<Output = T>,以便 T + T return 是 T:

impl<T: Add<Output = T>> Add for Matrix<T> {
    ...
}

另一种方法是使用 T 想要提供的任何输出:即您的添加将 return Matrix<T::Output>:

impl<T: Add> Add for Matrix<T>
{
    type Output = Matrix<T::Output>;

    fn add(self, _rhs: Matrix<T>) -> Matrix<T::Output>
    {
        assert!(self.rows == _rhs.rows && self.cols == _rhs.cols,
                "attempting to add matrices of different sizes");

        let mut res = Matrix {
            rows: self.rows,
            cols: self.cols,
            data : Vec::with_capacity(self.rows * self.cols),
        };

        for i in 0..self.rows*self.cols{
            res.data.push(self.data[i] + _rhs.data[i]);
        }
        res
   }
}

但是,这两个都遇到了一个问题:

<anon>:23:27: 23:39 error: cannot move out of indexed content
<anon>:23             res.data.push(self.data[i] + _rhs.data[i]);
                                    ^~~~~~~~~~~~
<anon>:23:42: 23:54 error: cannot move out of indexed content
<anon>:23             res.data.push(self.data[i] + _rhs.data[i]);
                                                   ^~~~~~~~~~~~

Add/+ 运算符获取其参数的所有权,并且不能将所有权从具有直接索引的向量中移出(通常,编译器无法判断它不会'以后不要尝试再次访问移出的索引,这将是一个安全问题)。幸运的是,有一个解决方案:向量支持移出迭代器,并且可以遍历 self_rhs 步进移出:

for (a, b) in self.data.into_iter().zip(_rhs.data.into_iter()) {
    res.data.push(a + b)
}

ab 变量都是 T 类型,即所有权已转移。


小记,其实可以"iteratorise"代码更,写:

fn add(self, _rhs: Matrix<T>) -> Matrix<T::Output>
{
    assert!(self.rows == _rhs.rows && self.cols == _rhs.cols,
            "attempting to add matrices of different sizes");

    let data = self.data.into_iter()
         .zip(_rhs.data.into_iter())
        .map(|(a,b)| a + b)
        .collect();
    Matrix {
        rows: self.rows,
        cols: self.cols,
        data: data
    }
}