在实现原始固定大小的矢量类型(例如float2
)时,我想支持Add
和Sub
特征。稍后,我会支持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 */
虽然这允许在不解除引用的情况下编写表达式。枚举每个组合变得相当繁琐,特别是在添加更多操作时。类型(float3
,float4
...)。
是否有一种普遍接受的方式......
或者开发人员是否期望:
注意,我目前是初学者,我已经检查过Rust中一些非常高级的数学库,他们已经超越了我的头脑,而我可以使用它们 - 我想要了解如何为我自己的类型编写运算符重载。
答案 0 :(得分:6)
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)
}
}
}
}
为引用创建特征的包装实现肯定是有效的,这些引用只是取消引用并调用面向值的版本。
答案 1 :(得分:0)
我建议您为此目的使用impl_os条板箱,请参见that other answer that I wrote。