2015-04-29 2 views
1

Чтобы узнать о Rust, я создаю свой класс Matrix. Моя реализация оных черта заключается в следующем:Несоответствующие типы при реализации признака

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 реализует Добавить но в любом месте я пытаюсь это сделать, либо получаю ту же ошибку или ошибку синтаксического анализа.

Мое определение матрицы кстати

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

ответ

4

Использование T: Add как оценка говорит, что можно написать T + T, но это не накладывает никаких ограничений на тип, который приведет от того, в частности, , это может быть не T. Вы полагаетесь на это T, чтобы иметь возможность вернуться Matrix<T>.

Один подход будет требовать, чтобы T: Add<Output = T>, так что T + T возвращает T:

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

Другой подход должен был бы вместо этого работать с тем, что выход T хочет дать: то есть ваше добавление будет возвращать 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) 
} 

a и b переменные оба типа 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 
    } 
} 
+0

Спасибо. Я понимаю, что нужно указать, что тип вывода также является T, но я, очевидно, еще не полностью владею правами на grokked. Требуется больше исследований ... – tomsgd

Смежные вопросы