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

Why do I need to dereference a variable when comparing it but not when doing arithmetic?

我有以下代码:

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 > limit) 中取消引用 prime,而在第一种情况 (number % prime == 0) 中不需要这样做?

%< 都是运算符,它们接受两个数字和 return 一些东西。唯一的区别似乎在于它们 return(数字与布尔值)。虽然 确实 解释了使代码工作所需的条件(所有重载的实现,最好在标准库中),但它 不会 说明为什么它对 a % b 有效。这些运算符之间有根本区别吗?还是还没有实施?

因为您可以 Rem 实现不同类型和核心库实现

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

这对于 PartialOrdOrd 特征是不可能的,所以你需要比较完全相同的类型,在本例中 i32,这就是为什么需要取消引用。

比较运算符的行为实际上与算术运算符不同。当查看特征定义时,差异变得很明显。例如,这里是 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.

来移动或复制它们

由于这种差异,如果我们为类型 A 实现 PartialEq,我们不仅可以比较 AA,还可以 &A&A 由于操作数的解引用强制。另一方面,对于 Add 我们需要一个单独的实现来添加 &A&A.

我无法回答为什么标准库实现 "mixed" 版本用于算术运算符的引用和值,而不是用于比较。我看不出后者无法完成的根本原因。