How to implement idiomatic operator overloading for values ​​and references in Rust?

When implementing a primitive vector type of fixed size (e.g. float2 ), I want to support the Add and Sub attributes. Later I want to support Mul and *Assign .

Picking up the documentation and other examples, I came up with the following:

 use std::ops::{Add, Sub}; #[derive(Copy, Clone)] struct float2(f64, f64); impl Add for float2 { type Output = float2; fn add(self, _rhs: float2) -> float2 { float2(self.0 + _rhs.0, self.1 + _rhs.1) } } impl Sub for float2 { type Output = float2; fn sub(self, _rhs: float2) -> float2 { float2(self.0 - _rhs.0, self.1 - _rhs.1) } } 

This works for basic examples, but in practice I often float2 across links passed as arguments, as well as local float2 on the stack.

To mix them, I needed either:

  • Link variables (OK, but makes the code a little less readable).
  • Declare an operator by overloading link combinations.

Example:

 impl<'a, 'b> Add<&'b float2> for &'a float2 { type Output = float2; fn add(self, _rhs: &'b float2) -> float2 { float2(self.0 + _rhs.0, self.1 + _rhs.1) } } impl<'a> Add<float2> for &'a float2 { type Output = float2; fn add(self, _rhs: float2) -> float2 { float2(self.0 + _rhs.0, self.1 + _rhs.1) } } impl<'b> Add<&'b float2> for float2 { type Output = float2; fn add(self, _rhs: &'b float2) -> float2 { float2(self.0 + _rhs.0, self.1 + _rhs.1) } } /*... and again for Sub */ 

Although this allows you to write expressions without dereference. listing of each combination becomes quite tedious, especially when adding more operations and types ( float3 , float4 ...).

Is there a generally accepted way ...

  • Automatic type enforcement for operator overloading?
  • Use macros or any other language feature to avoid tedious repetition?

Or developers are also expected to:

  • Explicitly access variables as references as needed.
  • Explicitly deactivate variables if necessary.
  • Write many repetitive operator overload functions.

Please note that I am currently a beginner, I checked out some pretty advanced math libraries in Rust, they went through my head, although I could use them. I would like to understand how to write operator overloading for my own types.

+9
operator-overloading rust
source share
2 answers

The great thing about Rust is that it is open source. This means that you can see how the authors of the language solved the problem. The closest analogue are primitive integer types :

 macro_rules! add_impl { ($($t:ty)*) => ($( #[stable(feature = "rust1", since = "1.0.0")] impl Add for $t { type Output = $t; #[inline] fn add(self, other: $t) -> $t { self + other } } forward_ref_binop! { impl Add, add for $t, $t } )*) } 

forward_ref_binop defined as :

 macro_rules! forward_ref_binop { (impl $imp:ident, $method:ident for $t:ty, $u:ty) => { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> $imp<$u> for &'a $t { type Output = <$t as $imp<$u>>::Output; #[inline] fn $method(self, other: $u) -> <$t as $imp<$u>>::Output { $imp::$method(*self, other) } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> $imp<&'a $u> for $t { type Output = <$t as $imp<$u>>::Output; #[inline] fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { $imp::$method(self, *other) } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a, 'b> $imp<&'a $u> for &'b $t { type Output = <$t as $imp<$u>>::Output; #[inline] fn $method(self, other: &'a $u) -> <$t as $imp<$u>>::Output { $imp::$method(*self, *other) } } } } 

Of course, it is permissible to write attribute wrapper implementations for links that simply dereference and invoke a value-oriented version.

+6
source share

I advise you to use the impl_os box for this purpose, see the other answer I wrote .

0
source share

All Articles