operator-overloading - 如何在Rust中为值和引用实现惯用运算符重载?

标签 operator-overloading rust

在实现原始的固定大小的矢量类型(例如float2)时,我要支持AddSub特性。稍后,我将要支持Mul*Assign

在查阅文档和其他示例时,我想到了这一点:

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)
    }
}

这适用于基本示例,但是我发现在实践中,我通常会最终将引用作为参数以及堆栈中的本地float2传入。

为了混合这些,我需要:
  • 取消引用变量(可以,但是会使代码的可读性降低)。
  • 也声明运算符重载引用的组合。

  • 例子:
    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 */
    

    虽然这允许编写表达式而无需取消引用。枚举每种组合非常繁琐,尤其是在添加更多操作和类型(float3float4 ...)时。

    是否有一种普遍接受的方法来...
  • 自动强制类型以运算符重载吗?
  • 使用宏或语言的其他功能来避免繁琐的重复吗?

  • 还是期望开发人员:
  • 根据需要显式访问变量作为引用。
  • 根据需要明确取消引用变量。
  • 写很多重复的运算符重载函数。


  • 注意,我目前是一个初学者,我已经在Rust中检查了一些相当高级的数学库,虽然我可以使用它们,但是它们已经超出了我的理解范围-我想了解如何为自己的类型编写运算符重载。

    最佳答案

    Rust的伟大之处在于它是开源的。这意味着您可以看到该语言的作者如何解决问题。最接近的类似物是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 is 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)
                }
            }
        }
    }
    

    为引用简单地取消引用并调用面向值(value)的版本的特征编写包装实现当然是有效的。

    关于operator-overloading - 如何在Rust中为值和引用实现惯用运算符重载?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65168263/

    相关文章:

    rust - rust 同步 channel 更新错误 'nightly --- (error reading rustc version)'

    rust - 结果得到意外的类型参数

    c++ - 词法范围的排序行为

    c++ - 如何覆盖运算符<<?

    使用rust 生命周期 &'a T

    enums - Rust proc_macro_derive(带有syn crate)生成用于匹配的枚举变量

    serialization - 为什么在使用带有结构变体的枚举手动实现的序列化序列化为 TOML 时出现 UnsupportedType 错误?

    c++ - 模板化重载运算符不明确

    c++ - "no ' operator++(int) ' declared for postfix '++ ' [-fpermissive]"枚举

    C++ << 运算符重载和 Arduino 模板