Почему мне нужно разыменовывать переменную при сравнении, а не при выполнении арифметики? - PullRequest
0 голосов
/ 09 января 2019

У меня есть следующий код:

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

И %, и < являются операторами, которые принимают два числа и возвращают что-то. Единственная разница, кажется, в том, что они возвращают (число против логического). Хотя Почему невозможно сравнить заимствованное целое число с целым литералом? объясняет , что требуется для работы кода (реализации для всех перегрузок, в идеале в стандарте библиотека), он не говорит, почему он работает для a % b. Есть ли принципиальная разница между этими операторами? Или это просто еще не реализовано?

Ответы [ 2 ]

0 голосов
/ 09 января 2019

Операторы сравнения на самом деле ведут себя не так, как арифметические операторы. Разница становится очевидной при взгляде на определения признаков. Например, вот черта PartialEq 1002 *

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, но также &A и &A в силу разыменного приведения для операндов. С другой стороны, для Add нам нужна отдельная реализация, чтобы иметь возможность добавлять &A и &A.

Я не могу ответить, почему в стандартной библиотеке реализованы «смешанные» версии для справки и значения для арифметических операторов, а не для сравнения. Я не вижу фундаментальной причины, по которой последнее не может быть сделано.

0 голосов
/ 09 января 2019

Поскольку у вас может быть Rem реализация для разных типов, а базовая библиотека реализует

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

Это невозможно для черт PartialOrd и Ord, поэтому вам нужно сравнивать абсолютно одинаковые типы, в данном случае i32, поэтому существует требование для разыменования.

...