std
's range support is missing ranges with explicitly specified increments. There is Iterator::step_by
but that is subtly different: it skips values (so cannot be used to iterate downwards). (0 .. -10).step_by(2)
is empty and (0 .. -10).step_by(-2)
is a compile error. None of this works with floating point numbers because they don't implement Step
.
The easiest way to write this at the moment, that I found, is some construction involving Iterator::successors
.
Thinking about how to fix this, I think we probably don't want to do anything funky syntax-wise (eg, Feature idea: impl Iterator for tuple (1,2..n) as range with step). We really just want to be able to write:
for v in (0. ..= 2.5).adding(0.5) { ... }
for v in (0 .. -10).adding(-1) { ... }
for v in (0. .. 10.1).adding(1./3.) { ... }
I think this is easily implemented by providing an adding
method on Range
, RangeFrom
and RangeInclusive
, and a corresponding RangeAdding
struct. Something like:
struct RangeAdding<Idx> {
next: Idx,
step: Idx,
bound: Bound<Idx>,
};
impl<Idx> Iterator for RangeAdding<Idx>
where Idx: Add<Rhs=Idx,Output=Idx> { ... }
The docs for Iterator::step_by
ought to refer to adding
and vice versa.
The docs for adding
ought to mention the floating point rounding issue. This issue is not entirely straightforward and does present a hazard for naive use. But the algorithms for avoiding it typically involve substituting multiplication for addition, or explicitly choosing a bound in between expected values. If the user wants multiplication they can write (0 ..= 30).map(|x| x as f64 * (1./3.)) or something. I don't think we want to provide sugar for that. I also don't think that we should automatically adjust the offset; that would be too confusing,
We don't need .subtracting
because either the type is signed and you can just write .adding(-whatever)
, or you can use .step_by
and .rev
.