在实现基本的固定大小向量类型(例如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 */

而这允许在不取消引用的情况下编写表达式.列举每种组合会变得相当乏味,尤其是在添加更多操作时&amp;类型(float3float4…).

有没有一种被普遍接受的方法...

  • 为运算符重载自动强制类型?
  • 使用宏或语言的其他功能来避免冗长的重复?

还是希望开发者:

  • 根据需要显式访问变量作为引用.
  • 根据需要显式取消引用变量.
  • 编写大量重复的运算符重载函数.

Note, I'm currently a beginner, I've checked some quite advanced math libraries in Rust, they're way over my head, while I could use them - I would like to understand how to write operator overloading for my own types.

推荐答案

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

为引用编写traits的包装器实现当然是有效的,这些引用只是取消引用并调用面向值的版本.

Rust相关问答推荐

访问Rust中的隐藏变量

修改切片/引用数组

使用Clap时如何将String作为Into Str参数传递?

定义采用更高级类型泛型的性状

用 rust 蚀中的future 展望 struct 的future

一种随机局部搜索算法的基准(分数)

AXUM一路由多个不包括URL的参数类型

允许 rust 迹 struct 条目具有多种类型

在 Rust 中,在需要引用 self 的 struct 体方法中使用闭包作为 while 循环条件

.在 Rust 模块标识符中

Rust 并行获取对 ndarray 的每个元素的可变引用

Rust 中指向自身的引用如何工作?

为什么需要同时为值和引用实现`From`?方法不应该自动解引用或borrow 吗?(2023-06-16)

从光标位置旋转精灵

&str 的编译时拆分是否可能?

If let expression within .iter().any

在空表达式语句中移动的值

如何为枚举中的单个或多个值返回迭代器

在 Rust 中有条件地导入?

如何阅读 HttpRequest 主体