如何才能要求对泛型类型的引用与泛型类型进行比较?

时间:2017-10-20 15:25:40

标签: rust

我试图实现依赖于模幂运算的算法。我找不到像u64这样的原生类型的任何模幂运算构造(仅适用于bigints),所以我认为我编写了标准modular exponentiation by repeated squaring method

这是我想出的:

fn powm(base: &u64, exponent: &u64, modulus: &u64) -> u64 {
    if *modulus == 1u64 {
        0
    } else {
        let mut result = 1;
        let mut base = self % modulus;
        let mut exp = *exponent;
        while exp > 0 {
            if exp % 2 == 1 {
                result = (result * base) % modulus;
            }
            exp >>= 1;
            base = (base * base) % modulus;
        }
        result
    }
}

这很好用。现在,我想将此功能设为通用,以便它也适用于u64以外的数字类型。这是我开始有点迷失的地方。

我找到了num个包,它具有Num个特征,指定了基本的数字操作。在分离出新的PowM特征并创建一堆特征边界后,我最终得到:

extern crate num;

use num::Num;
use std::ops::{ShrAssign,Rem};

pub trait PowM {
    fn powm(&self, exponent: &Self, modulus: &Self) -> Self;
}

pub trait Two {
    fn two() -> Self;
}

impl Two for u64 {
    fn two() -> u64 { return 2u64 }
}

impl Two for usize {
    fn two() -> usize { return 2usize }
}

impl<T> PowM for T 
    where T: Num + Two + ShrAssign<T> + Rem<T> + PartialOrd<T> {
    fn powm(&self, exponent: &T, modulus: &T) -> T {
        if modulus == T::one() {
            T::zero()
        } else {
            let mut result = T::one();
            let mut base = *self % *modulus;
            let mut exp = *exponent;
            while exp > T::zero() {
                if exp % T::two() == T::one() {
                    result = (result * base) % *modulus;
                }
                exp >>= T::one();
                base = (base * base) % *modulus;
            }
            result
        }
    }
}

编译器提出的唯一抱怨如下

error[E0277]: the trait bound `&T: std::cmp::PartialEq<T>` is not satisfied
   |
30 |         if modulus == T::one() {
   |                    ^^ can't compare `&T` with `T`
   |
   = help: the trait `std::cmp::PartialEq<T>` is not implemented for `&T`
   = help: consider adding a `where &T: std::cmp::PartialEq<T>` bound

我试图添加特征界限,但最终追逐很多关于生命周期的编译器错误,我还不完全理解,最终坚持以下内容:

impl<'a, T> PowM for T 
    where T: 'a + Num + Two + ShrAssign<T> + Rem<T> + PartialOrd<T>,
          &'a T: PartialEq<T> {
    fn powm(&self, exponent: &T, modulus: &T) -> T {
        if modulus == T::one() {
[...]

仍然会出错。我该如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

您可以忽略该问题,并将引用与非引用的引用或非引用进行比较:

if modulus == &T::one() {
// Or
if *modulus == T::one() {

或者您可以使用更高排名的特质界限

impl<T> PowM for T
where
    T: Num + Two + ShrAssign<T> + Rem<T> + PartialOrd<T>,
    for <'a> &'a T: PartialEq<T>,
{
    // ...
}

在任何一种情况下,您都需要T实施Copy或实施Clone,然后向.clone()添加适当的调用。

另见: