我有以下代码:
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
。这些运算符之间有根本区别吗?还是只是尚未实施?
答案 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
,我们不仅可以比较A
和A
,而且可以比较{{1} }和&A
依靠操作数的反强制。另一方面,对于&A
,我们需要一个单独的实现才能添加Add
和&A
。
我无法回答为什么标准库实现“混合”版本以作为算术运算符的参考和值,而不是用于比较。我看不出无法完成后者的根本原因。
答案 1 :(得分:1)
因为您可以使用Rem
实现不同的类型,并且核心库可以实现
impl<'a> Rem<&'a i32> for i32 { /* … */ }
对于PartialOrd
和Ord
特征,这是不可能的,因此您需要比较完全相同的类型,在这种情况下为i32
,这就是为什么需要取消引用的原因。