gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-11-29 07:44:47 25 4
gpt4 key购买 nike

当实现原始固定大小向量类型(例如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)
}
}
}
}

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

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

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com