2014-11-07 12 views
22

Właśnie wziąłem nurka w Rust i chcę wykonać podstawowe funkcje matematyczne, które są ogólne. Mam następujący is_prime funkcję:Jak utworzyć funkcję is_prime, która jest generyczna na różne typy liczb całkowitych?

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 
} 

Co zajęłoby dla mnie, aby móc przejść isize, i64, usize itd jako argumenty? Przeczytałem przez Rust guide na stronie głównej, ale nie jestem pewien, jak zastosować idee cech do mojego celu tutaj.

Odpowiedz

22

Ogólne typy liczb mogą być dość uciążliwe w pracy, ale gdy już się z nimi uporają, nie wydają się zbyt złe, choć trochę bardziej szczegółowe. Standardowymi cegiełkami do takich metod są cechy z the num crate z crates.io, w szczególności Num, Zero i One, jak również biblioteka standardowa std::cmp::PartialOrd.

Literały numeryczne nie mogą być rodzajowe w żadnym typie liczbowym; muszą być wykonane za pomocą wywołania metody cech; Zero::zero() i One::one() będą wystarczające dla większości celów - tutaj liczby, które chcemy uzyskać, to 0, 1, 2, 3, 5 i 6, które są znakomicie osiągalne dzięki tym elementom konstrukcyjnym. Możesz również stworzyć własną cechę za pomocą metod statycznych, tworząc te wartości i zaimplementować je dla dowolnych typów liczb, które chcesz, ale zrobienie tego z gwarancją, że jest to gwarantowane przez Num, jest lepszym pomysłem.

Podstawowa procedura jest, aby określić parametry typu rodzajowego jako oparte na Num (i PartialOrd jeśli piszesz nierówności na temat wartości tego typu, takie jak i * i <= n) i zastępuje żadnych literałów liczbowych z nich zbudowanych od zera do jednego, jak pokazuje to na początku poniższej metody kilka półtk zdań let. To zwykle wystarczy.

Oto, co skończy się dla tej konkretnej metody:

// 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 
} 
+5

Zamiast 'Num' cechę jako ograniczenie, to również możliwość korzystania z podstawowych cech, które są rzeczywiście potrzebne:' N: PartialEq + PartialOrd + Dodaj + SUB + Mul + Rem + One + Zero'. 'Num' to po prostu wygodny skrót. –

15

Aby dodać odpowiedź Chris Morgan, można użyć num::NumCast::from oddać do rodzajowego typu numer, pod którym za pomocą Zero i One byłoby niewłaściwe. W twoim przypadku:

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();