简体   繁体   中英

Mismatched types when implementing a trait

To learn Rust, I'm building my own Matrix class. My implementation of the Add trait is as follows:

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
   }
}

but i get the following error

       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]);
                                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~

Going by the error report, I guess that I need to indicate somewhere else that T implements the Add trait but anywhere I try to do this I either get the same error or a parsing error.

My definition of Matrix by the way is

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

Using T: Add as a bound says that one can write T + T , but it doesn't place any restriction on the type that will result from that, in particular, it may not be T . You're relying on it being T to be able to return Matrix<T> .

One approach would be to require that T: Add<Output = T> , so that T + T returns a T :

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

Another approach would be to instead work with whatever output T wants to give: ie your addition would 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
   }
}

However, both of these meet a problem:

<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 /the + operator takes ownership of its arguments, and one cannot move ownership out of a vector with direct indexing (in general, the compiler can't tell that one won't try to access a moved-out index again, later, which would be a safety problem). Fortunately, there's a solution: vectors support a moving-out iterator, and one can walk over self and _rhs moving out in lock-step:

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

The a and b variables are both of type T , ie ownership has moved.


Minor note, one can actually "iteratorise" the code even more, writing:

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
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM