如何在实现特征时对类型设置特征约束?

时间:2015-11-03 16:19:31

标签: rust traits

我有一个产生斐波纳契数的迭代器。我将类型限制为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}时,我被告知模块不存在。

1 个答案:

答案 0 :(得分: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时,你移动 valuenext的{​​{1}}导致了self错误。

由于add的定义具有此方法签名,因此无法移动值:

fn add(self, rhs: RHS) -> Self::Output;
RHS案例中的

Add只是Self。因此,为了将N限制为只能以较少的开销进行复制的类型,我添加了Copy特征作为限制。

OP提到了一个有趣的观点:是否有可能为特征添加别名?总之没有。 你可能创造一个新的特征:

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

但是你必须为你想要的所有类型实现这个特性。即i32不会自动实施SimpleAdd。但如果你愿意的话,你可以用泛型做到:

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

所以上面两个块会让你得到与特征别名相同的东西,但这看起来很麻烦。