Дело в том, что, как и сказал компилятор, вы пытаетесь использовать значение
после его перемещения.
Рассмотрим участок кода.
// умножаем слой на предыдущую матрицу
buf = v.mat_mul(&buf);
// результат записываем в вектор
result.push(buf);
На первой строчке вы определяете новое значение переменной. На второй - перемещаете значение в вектор.
После перемещения значение в переменной считается недействительным, т.к. его использование может нарушить безопасность памяти. Это один из основных принципов семантики владения.
Отвечая на ваш второй вопрос: да, клонирование - то, что вам нужно использовать в данном случае.
// умножаем слой на предыдущую матрицу
buf = v.mat_mul(&buf);
// результат записываем в вектор
result.push(buf.clone());
Однако, клонирование - операция дорогая. Учитывая, что для умножения нужна всего-лишь иммутабельная ссылка на матрицу, мы можем переписать код следующим образом:
// вектор, где будут хранится произведения матриц
let mut result = vec![];
for v in layers {
// пытаемся достать предыдущую матрицу
let previous_matrix = match result.last() {
Some(last) => last,
// а если таковой нет - ей станет входная
None => &input,
};
// умножаем слой на предыдущую (или входную) матрицу
let next_matrix = v.mat_mul(previous_matrix);
result.push(next_matrix);
}
Метод
Vec::<T>::last
возвращает
Option<&T>
, которая содержит ссылку на последний элемент ветора, если таковой существует. Его сложность O(1), поэтому по поводу ухудшения производительности можно не беспокоиться.
Это именно то, для чего и создавалась переменная-буфер. Теперь нам не нужно производить лишнее клонирование.