I have a simple struct that should implement basic math operators. Initially I didn't want these to consume the operands, so I implemented the traits for references, for example for Add
:
impl<'a, 'b> Add<&'b MyType> for &'a MyType {
type Output = MyType;
fn add(self, rhs: &'b MyType) -> Self::Output {
// Implementation...
}
}
This allows me to do:
let result = &v1 + &v2;
Where v1
and v2
are of type MyType
.
Then I realized that sometimes it is syntactically more convenient to consume the operands, for example when doing:
let result = &v1 + &v2 + &v3;
Because there is an intermediate result the above won't compile and you have to do:
let result = &v1 + &(&v2 + &v3);
So I ended up implementing the other permutations of move and borrow, which just defer to the first one:
impl<'a> Add<&'a MyType> for MyType {
type Output = MyType;
fn add(self, rhs: &'a MyType) -> Self::Output {
&self + rhs
}
}
impl<'a> Add<MyType> for &'a MyType {
type Output = MyType;
fn add(self, rhs: MyType) -> Self::Output {
self + &rhs
}
}
impl Add<MyType> for MyType {
type Output = MyType;
fn add(self, rhs: MyType) -> Self::Output {
&self + &rhs
}
}
This works, but is cumbersome.
I looked for an easier way, such as using Borrow<T>
:
impl<B> Add<B> for B
where
B: Borrow<MyType>,
{
type Output = MyType;
fn add(self, rhs: B) -> Self::Output {
// Implementation...
}
}
But that won't compile, understandably, due to type parameter
B must be used as the type parameter for some local type
.
Are there any other tricks to avoid having all these boilerplate implementations for Add
/Sub
/Mul
/Div
, etc?
Update:
@EvilTak made a suggestion in the comments which cuts down on the boilerplate combinations by implementing the B: Borrow<MyType>
version on MyType
and &MyType
explicitly. This is a good improvement:
impl<'a, B> Add<B> for &'a MyType
where
B: Borrow<MyType>,
{
type Output = MyType;
fn add(self, rhs: B) -> Self::Output {
// Implementation...
}
}
impl<B> Add<B> for MyType
where
B: Borrow<MyType>,
{
type Output = MyType;
fn add(self, rhs: B) -> Self::Output {
&self + rhs
}
}