有没有办法自动借用重载的运算符?

问题描述 投票:0回答:3

我正在尝试在 Rust 中实现一个基本的多项式类型,并使用用于数学运算的重载运算符。到目前为止,我可以通过重载运算符来实现加法、减法等基本运算。问题是,我想通过引用获取操作数以避免不必要的副本。 IE。 :

impl ops::Add for &Polynomial {
    type Output = Polynomial;
    fn add(self, other: Self) -> Polynomial {
        let mut result = self.clone();
        for (power, coeff) in other.coefficients.iter().enumerate() {
            result.add_coeff(power, *coeff);
        }
        result
    }
}
impl ops::Sub for &Polynomial {
    //  Implementation
    //  ...
}
impl ops::Mul for &Polynomial {
    //  Implementation
    //  ...
}
//  Etc.

这按预期工作,但是它迫使用户每次都显式借用操作数,随着表达式变得更加复杂,这变得不太可读:

let (quotient, remainder) = p2.div_rem(&p1);

assert_eq!(&(&quotient * &p1) + &remainder, p2);

//  Even worse example found on the internet.
//  Note that you need to explicitly borrow each and every intermediate result :
let result = &(&(&a * &b) + &(&c * &d)) / 2;

而不是最后两行,我认为如果我可以写成:

,它会更清晰易读。
assert_eq!(quotient * p1 + remainder, p2);

let result = (a * b + c * d) / 2;

…并让借用“自动”发生(就像当您调用一个将

&self
作为任何值的第一个参数的方法时所做的那样:它会自动且隐式地借用,而无需显式借用它)。

但是我不知道是否可以这样做,或者如何做?

rust
3个回答
4
投票

据我所知,不,没有简单的方法可以做到这一点,因为 Rust 引用总是显式的,而不是隐式的,这是由于两种设计选择(即避免 C++ 引用的相同设计问题,这是奇怪)和必要性(由于借用检查器)。

T, &T, &mut T, *const T
,...都是不同的类型,具有不同的语义,因此允许
impl ops::Add for &Polynomial
也适用于
Polynomial
基本上意味着
impl ops::Add for &T
将自动为
ops::Add
实现
T
,这可以导致非常奇怪且可能不安全的结果,特别是如果相反的情况也是如此。那
&mut
呢?
&mut T
会自动衰减为
&
吗?这对借用本身的生命周期有何影响?

此外,在非

ops::Add
值类型上实现
Copy
非常奇怪,因为运算符会导致其操作数被移入 - 这绝对不是人们在使用
+
时大多数时候所期望的。


2
投票

标准方法是为引用和值定义算术运算。这对于实现来说可能有点乏味(通常涉及宏来减少代码重复),但为 API 用户提供了最大的可用性。

用户可以编写看起来很常规的代码,而无需额外的借用,但也可以选择在想要保留该值以供以后使用时进行借用(从而避免不必要的复制)。例如,使用

num_bigint
板条箱,所有这些都可以工作:

    assert!(BigUint::from(1u8) + BigUint::from(1u8) == BigUint::from(2u8));
    assert!(&BigUint::from(1u8) + &BigUint::from(1u8) == BigUint::from(2u8));
    assert!(BigUint::from(1u8) + &BigUint::from(1u8) == BigUint::from(2u8));
    assert!(&BigUint::from(1u8) + BigUint::from(1u8) == BigUint::from(2u8));

1
投票

您可以使用

std::borrow::Borrow
实现大部分目标,它允许您在正确的运算符是借用或移动时实现运算符。这是有效的,因为
Borrow<T>
具有
&T
的全面实现,但实际上什么也不做。不幸的是,你不能用一种特质来替代另一种特质。因此,对于左运算符是借用和移动的情况,您需要一个
impl
impl

© www.soinside.com 2019 - 2024. All rights reserved.