如何创建一个在各种整数类型上通用的is_prime函数?

时间:2014-11-07 22:01:04

标签: rust traits

我刚刚深入研究了Rust并希望制作一些通用的基本数学函数。我有以下is_prime函数:

fn is_prime(n: i64) -> bool {
    if n == 2 || n == 3 {
        return true;
    } else if n % 2 == 0 || n % 3 == 0 {
        return false;
    }

    let mut i = 5i64;
    let mut w = 2i64;
    while i*i <= n {
        if n % i == 0 {
            return false;
        }
        i += w;
        w = 6 - w;
    }
    true
}

能够将isizei64usize等作为参数传递给我需要什么?我已经阅读了主页上的Rust guide,但我不确定如何将特征的想法应用到我的目标中。

2 个答案:

答案 0 :(得分:25)

通用数字类型可能会非常麻烦,但是一旦你掌握了它们,它们就不会太糟糕,虽然更加冗长。这些方法的标准构建块是来自crates.io的the num crate中的特征,最值得注意的是NumZeroOne,以及标准库{{3} }}。

数字文字不能超过任何数字类型;它们必须用特征方法调用完成; std::cmp::PartialOrdZero::zero()足以满足大多数目的 - 这里我们想要的数字是0,1,2,3,5和6,这些构建块可以显着地实现。您也可以使用静态方法创建自己的特征,生成这些值,并为您喜欢的任何数字类型实现它,但是使用Num保证的更好的想法。

基本过程是将您的泛型类型参数指定为基于Num(如果您在该类型的值上编写不等式,例如PartialOrd),则指定i * i <= n,并替换任何带有从0和1构造的数字文字的数字文字,如下面方法开头的六个let语句所示。这通常就足够了。

以下是您对此特定方法的最终结果:

// You’ll also need the appropriate dependencies.num addition to Cargo.toml
extern crate num;

use num::Num;

fn is_prime<N: Num + PartialOrd + Copy>(n: N) -> bool {
    let _0 = N::zero();
    let _1 = N::one();
    let _2 = _1 + _1;
    let _3 = _2 + _1;
    let _5 = _2 + _3;
    let _6 = _3 + _3;
    if n == _2 || n == _3 {
        return true;
    } else if n % _2 == _0 || n % _3 == _0 {
        return false;
    }

    let mut i = _5;
    let mut w = _2;
    while i * i <= n {
        if n % i == _0 {
            return false;
        }
        i = i + w;
        w = _6 - w;
    }
    true
}

答案 1 :(得分:15)

要添加到Chris Morgan的答案,您可以使用num::NumCast::from转换为使用ZeroOne不合适的通用数字类型。在你的情况下:

use num::{Num, NumCast};

fn is_prime<N: Num + Ord + NumCast + Copy>(n: N) -> bool {
    let _0: N = NumCast::from(0usize).unwrap();
    let _1: N = NumCast::from(1usize).unwrap();
    let _2: N = NumCast::from(2usize).unwrap();
    let _3: N = NumCast::from(3usize).unwrap();
    let _4: N = NumCast::from(4usize).unwrap();
    let _5: N = NumCast::from(5usize).unwrap();
    let _6: N = NumCast::from(6usize).unwrap();