为什么在比较时需要取消引用变量,而在进行算术时却不需要取消引用?

时间:2019-01-08 21:32:35

标签: rust operators

我有以下代码:

fn example(known_primes: &[i32], number: i32, prime: i32, limit: i32) {
    let mut is_prime = true;

    for prime in known_primes {
        if number % prime == 0 {
            is_prime = false;
            break;
        }
        if *prime > limit {
            break;
        }
    }
}

当我在第一个条件(prime)中不需要这样做时,为什么我需要在第二个条件(*prime > limit)中对number % prime == 0取消引用?

%<都是带两个数字并返回值的运算符。唯一的区别似乎在于它们的返回值(数字与布尔值)。 Why isn't it possible to compare a borrowed integer to a literal integer? 没有解释了使代码正常工作所需的内容(所有重载的实现,理想情况下是在标准库中),而没有却说了为什么适用于a % b。这些运算符之间有根本区别吗?还是只是尚未实施?

2 个答案:

答案 0 :(得分:5)

比较运算符实际上的行为与算术运算符不同。当查看特征定义时,差异变得明显。例如,这是PartialEq特质

pub trait PartialEq<Rhs = Self>
where
    Rhs: ?Sized,
{
    fn eq(&self, other: &Rhs) -> bool;
    fn ne(&self, other: &Rhs) -> bool { ... }
}

Add特性

pub trait Add<RHS = Self> {
    type Output;
    fn add(self, rhs: RHS) -> Self::Output;
}

我们可以看到比较特征按参考值取操作数,而算术特征按值取操作数。这种差异反映在编译器如何转换运算符表达式上:

a == b   ==>   std::cmp::PartialEq::eq(&a, &b)
a + b    ==>   std::ops::Add::add(a, b)

比较操作数被视为位置表达式,因此它们永远不会移动值。另一方面,算术运算符的操作数被视为值表达式,因此根据操作数类型是否为Copy来移动或复制它们。

由于这种差异,如果我们为类型PartialEq实现A,我们不仅可以比较AA,而且可以比较{{1} }和&A依靠操作数的反强制。另一方面,对于&A,我们需要一个单独的实现才能添加Add&A

我无法回答为什么标准库实现“混合”版本以作为算术运算符的参考和值,而不是用于比较。我看不出无法完成后者的根本原因。

答案 1 :(得分:1)

因为您可以使用Rem实现不同的类型,并且核心库可以实现

impl<'a> Rem<&'a i32> for i32 { /* … */ }

对于PartialOrdOrd特征,这是不可能的,因此您需要比较完全相同的类型,在这种情况下为i32,这就是为什么需要取消引用的原因。