In my case I was wanting my step size to be a float value and Iterator::step_by is a usize...
The solution I'm doing at the moment is utilizing my own struct but I'm kind of surprised this is necessary.
struct FloatRange {
start: f64,
end: f64,
step: f64,
current: f64,
inclusive: bool,
precision: usize,
}
impl FloatRange {
fn new(start: f64, end: f64, step: f64, inclusive: bool, precision: usize) -> Self {
FloatRange {
start,
end,
step,
current: start,
inclusive: inclusive,
precision: precision,
}
}
fn round_to_precision(value: f64, precision: usize) -> f64 {
let factor = 10f64.powi(precision as i32);
(value * factor).round() / factor
}
}
impl Iterator for FloatRange {
type Item = f64;
fn next(&mut self) -> Option<Self::Item> {
if self.current > self.end {
None
} else if !self.inclusive && self.current == self.end {
None
} else {
let current = self.current;
self.current = FloatRange::round_to_precision(self.current + self.step, self.precision);
Some(current)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_float_range_noninclusive() {
let range = FloatRange::new(-1.0, 1.0, 0.2, false, 2);
let result: Vec<f64> = range.collect();
let expected = vec![-1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8];
assert_eq!(result, expected);
}
#[test]
fn test_float_range_inclusive() {
let range = FloatRange::new(-1.0, 1.0, 0.2, true, 2);
let result: Vec<f64> = range.collect();
let expected = vec![-1.0, -0.8, -0.6, -0.4, -0.2, 0.0, 0.2, 0.4, 0.6, 0.8, 1.0];
assert_eq!(result, expected);
}
}