So I've been trying to implement a library for vector and matrix maths, and I created some functions that worked alright but wanted to generalize for all number primitives and add the functionality into the normal operators.
My thought was that I'd create a container for a Vec<T>
, that can contain either number types (like i32
) or another container for Vec
, so that matrices where possible. Ergo:
#[derive(Clone, Debug)]
struct Mat<T>(Vec<T>);
Then, to add together two vecs of any number I implement 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
}
}
}
Edit: To further clarify, Mat::pop()
is just the unwrap function, though probably poorly named.
The basic scenario of adding together two vectors of any number seems to work.
#[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]);
}
But matrices are giving me a headache. For them, the add function looks very similar, except for the let Some(x)
statement:
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
}
}
}
The error message I get is:
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>`
So the compiler says that Add
might not be implemented for &Mat<T>
, but I thought that I've specified the bound so that it has that requirement in where T: Add<&'a Mat<T>
. To me it seems that whatever is in &a[i]
should have the Add trait implemented. What am I doing wrong here?
Just as extra clarification, my idea is that Add for &'a Mat<Mat<T>>
should be able to be called recursively until it boils down to the Vec
with an actual number type in it. Then the Add for &'a Mat<T>
should be called.