2015-11-03 45 views
2

我有一個產生斐波納契數字的迭代器。我將該類型限制爲u32,但現在我正努力使其對於任何數字類型都是通用的。如何在實現特質的同時在類型上放置特徵約束?

工作,非通用代碼:

struct Fib { 
    value: u32, 
    next: u32, 
} 

impl Fib { 
    fn new(a : u32, b : u32) -> Fib { 
     Fib { value : a, next : b } 
    } 
} 

impl Iterator for Fib { 
    type Item = u32; 

    fn next(&mut self) -> Option<u32> { 
     let value = self.value; 
     let next = self.value + self.next; 
     self.value = self.next; 
     self.next = next; 
     Some(value) 
    } 
} 


////////////////////////////////////////////////// 

fn main() { 

    let fib = Fib::new(1, 2); 

    let sum = fib.filter(|x| { x % 2 == 0 }) 
     .take_while(|&x| { x <= 4000000 }) 
     .fold(0, |sum, x| { sum + x }); 

    println!("{}", sum); 
} 

的問題是,Iterator的實現需要一個約束Num,但我不知道該如何表達這一點:

impl <T : Num> Iterator for Fib<T> { ... } 

產品:

use of undeclared trait name `Num` 

而當我嘗試use std::num::{Num}use num::traits::{Num},我被告知這些模塊不存在。

+0

呃... [那特質**不存在](http://doc.rust-lang.org/std/?search=Num)。錯誤信息在這裏很有用。 – Shepmaster

+0

我在這裏找到它:https://doc.rust-lang.org/num/num/traits/trait.Num.html 如何判斷哪些文檔已過期? –

+2

這是從編號,而不是從stdlib〜> https://crates.io/crates/num – contradictioned

回答

3

我不認爲你想要Fib是數字類型的泛型,但實現+運算符的類型。像這樣:

use std::ops::Add; 

struct Fib<N> 
where N: Add<Output = N> + Copy { 
    value: N, 
    next: N, 
} 

impl<N> Iterator for Fib<N> 
where N: Add<Output = N> + Copy { 
    type Item = N; 

    fn next(&mut self) -> Option<N> { 
     let next = self.value + self.next; 
     self.value = self.next; 
     self.next = next; 
     Some(next) 
    } 
} 

fn main() { 
    let fib_seq = Fib { 
     value: -1, 
     next: 1, 
    }; 

    for thing in fib_seq.take(10) { 
     println!("{}", thing); 
    } 
} 

Add是允許您使用+運營商和生產Output性狀。在這種情況下,N實現Add<Output = N>特徵,這意味着N + N將產生N類型的東西。

這聽起來像它,但是當你嘗試做self.next + self.value移動valuenextself導致錯誤。

你不能因爲附加的定義有這種方法的簽名不動的值脫身:

fn add(self, rhs: RHS) -> Self::Output; 

RHSAdd的情況下,僅僅是Self。所以爲了限制N它的類型,只需要很少的開銷就可以複製,我添加了Copy特徵作爲限制。

OP提到一個有趣的觀點:是否有可能混淆特質?總之沒有。 你可以作出新的特點:

trait SimpleAdd: Add<Output = Self> + Copy { 
} 

但隨後你就必須實現該特性對於所有你想要的類型。即i32不會自動執行SimpleAdd。但是你可以使用泛型做,如果你想:

impl<N> SimpleAdd for N 
where N: Add<Output = N> + Copy { 
} 

所以上面的兩個區塊,會得到同樣的事情,作爲一個特質別名,但它似乎是一個麻煩。

+0

謝謝。我剛剛發現我還需要'Copy'和'Num'一起,但我仍在研究是否這是正確的方法。 「添加」絕對是我想要的,但我已經在「官方」文檔中找到了不同版本的文檔,不再是語言的一部分,這很煩人。 –

+0

另外,我不知道'where'語法。那很棒! –

+2

要求'N'爲'Copy'不會超級通用。當然,你可以將其改爲「克隆」,但這會使代碼醜化。我可能會更喜歡'<'a,'b>&'a N:Add <&'b N,Output = N>'代替哪裏。這應該仍然可以使用內置類型,但也支持更復雜的用戶定義類型,既不是'Copy'又不便宜以克隆(像BigInt類型)。 – sellibitze

相關問題