如何在Rust中实现惯用运算符重载值和引用? [英] How to implement idiomatic operator overloading for values and references in Rust?

查看:104
本文介绍了如何在Rust中实现惯用运算符重载值和引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当实现基本的固定大小矢量类型(例如,float2)时,我想支持AddSub特性.稍后,我将要支持Mul*Assign.

When implementing a primitive fixed-size vector type (float2 for example), I want to support the Add and Sub traits. Later, I will want to support Mul and *Assign.

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

Looking up the documentation and other examples, I came up with this:

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传入.

This works for basic examples, however I found in practice I would often end up with references passed in as arguments as well as local float2's on the stack.

要混合这些,我需要:

  • 取消引用变量(可以,但是会使代码的可读性降低).
  • 也声明运算符重载引用的组合.

示例:

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

While this allows to write expressions without de-referencing. it becomes quite tedious to enumerate each combinations, especially when adding more operations & types (float3, float4...).

有没有一种普遍接受的方式...

Is there a generally accepted way to...

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

或者期望开发人员要么:

Or is it expected that developers either:

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

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

推荐答案

Rust的优点在于它是开源的.这意味着您可以看到该语言的作者如何解决问题.最接近的类似物是原始整数类型:

The great thing about Rust is that it's open source. This means you can see how the authors of the language have solved a problem. The closest analogue is 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是定义为:

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

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

It's certainly valid to write wrapper implementations of the traits for references that simply dereference and call the value-oriented version.

这篇关于如何在Rust中实现惯用运算符重载值和引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆