无法创建使用文字零的通用函数

时间:2015-01-14 20:40:04

标签: rust

我正在尝试编写类似于内置Range的Rust函数,但我想要的东西只能返回X个数字,并将其作为列表返回,这就是为什么我要尝试使这个功能:     extern crate num;

use num::Integer;

fn positions<T: Integer>(start: T, step: T, len: T) -> Vec<T> {
    (0..len).map(|i| start + step * i).collect()
}

fn main() {
    println!("{:?}", positions(10, 2, 10));
}

除了我收到编译错误:

error[E0308]: mismatched types
 --> src/main.rs:6:9
  |
6 |     (0..len).map(|i| start + step * i).collect()
  |         ^^^ expected integral variable, found type parameter
  |
  = note: expected type `{integer}`
             found type `T`
  = help: here are some functions which might fulfill your needs:
          - .div_floor(...)
          - .gcd(...)
          - .lcm(...)
          - .mod_floor(...)

error[E0308]: mismatched types
 --> src/main.rs:6:37
  |
6 |     (0..len).map(|i| start + step * i).collect()
  |                                     ^ expected type parameter, found integral variable
  |
  = note: expected type `T`
             found type `{integer}`

1 个答案:

答案 0 :(得分:4)

问题是0。我现在还不清楚确切的规则,但是我们是一般的:0是某种特定的整数类型,它可能与任何T相同或不同是。因此,编译器无法确定range的类型参数应该是什么。

您可以使用Zero::zero解决此问题:

fn positions<T: Integer>(start: T, step: T, len: T) -> Vec<T> {
    (T::zero()..len).map(|i| start + step * i).collect()
}

这为编译器提供了足够的余地来推断range的两个参数属于同一类型。但是,使用Range作为迭代器仍然不够:

error: no method named `map` found for type `std::ops::Range<T>` in the current scope
 --> src/main.rs:8:22
  |
8 |     (T::zero()..len).map(|i| start + step * i).collect()
  |                      ^^^
  |
  = note: the method `map` exists but the following trait bounds were not satisfied: `T : std::iter::Step`, `&'a T : std::ops::Add`, `std::ops::Range<T> : std::iter::Iterator`

不幸的是,从Rust 1.17开始,Step trait不稳定,所以目前还没有好办法用稳定的Rust来解决这个问题。

使用不稳定的Rust,您可能需要Step的实现:

#![feature(step_trait)]

extern crate num;

use num::Integer;

fn positions<T>(start: T, step: T, len: T) -> Vec<T>
    where T: Integer + std::iter::Step + Copy,
          for<'a> &'a T: std::ops::Add<Output = T>
{
    (T::zero()..len).map(|i| start + step * i).collect()
}

fn main() {
    println!("{:?}", positions(10, 2, 10));
}

需要要求T可以复制(或克隆,如果你愿意),因为AddMul的实现会消耗操作数按值计算,这意味着start + step * i只能被调用一次,除非需要多次调用。