I am trying to write a Rust function that is similar to the built-in Range
, but I want something that will return only X numbers, and return it as a list, which
The problem is 0
. I'm unclear on the exact rules right now, but let's be general: 0
is of some specific integer type, which may or may not be the same thing as whatever T
is. Thus, the compiler can't work out what the type parameter to range
is supposed to be.
You can resolve this by using Zero::zero:
fn positions(start: T, step: T, len: T) -> Vec {
(T::zero()..len).map(|i| start + step * i).collect()
}
This gives the compiler enough leeway to infer that the two arguments to range
are of the same type. However, that's still not enough to use Range
as an iterator:
error: no method named `map` found for type `std::ops::Range` 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 : std::iter::Iterator`
Unfortunately, as of Rust 1.17, the Step trait is unstable, so there's currently no good way to solve this problem using stable Rust.
Using unstable Rust, you can require implementations of Step
:
#![feature(step_trait)]
extern crate num;
use num::Integer;
fn positions(start: T, step: T, len: T) -> Vec
where T: Integer + std::iter::Step + Copy,
for<'a> &'a T: std::ops::Add
You also need to require that T
can be copied (or cloned, if you like) because the implementation of Add
and Mul
consumes the operands by value, which would mean that start + step * i
could only be called once, except it needs to be called multiple times.