How should I go if I want to iterate with a custom step in stable Rust? Essentially something like the C/C++
for (in
Since this question was asked, the itertools crate, has become fairly standard as a dependency. You can do what you want very simply with the step() method:
extern crate itertools; // 0.7.8
use itertools::Itertools;
fn main() {
for i in (0..=10).step(2) {
println!("i = {}", i);
}
}
In your Cargo.toml
:
[dependencies]
itertools = "0.7.8"
Iterator::step_by is now stable:
fn main() {
for i in (0..100).step_by(2) {
println!("{}", i);
}
}
You can always write it out the old-fashioned way:
fn main() {
let mut i = 0;
while i < 100 {
println!("i: {}", i);
i += 2;
}
}
Which can then be abstracted:
use std::ops::Add;
fn step_by<T, F>(start: T, end_exclusive: T, step: T, mut body: F)
where
T: Add<Output = T> + PartialOrd + Copy,
F: FnMut(T),
{
let mut i = start;
while i < end_exclusive {
body(i);
i = i + step;
}
}
fn main() {
step_by(0, 100, 2, |i| {
println!("i: {}", i);
})
}
Interesting historical side note, I believe that originally all the looping was done with closures like this, before iterators became extremely prevalent.
You can then take this and make it into an iterator:
use std::ops::Add;
struct StepBy<T> {
start: T,
end_exclusive: T,
step: T,
}
impl<T> StepBy<T> {
fn new(start: T, end_exclusive: T, step: T) -> Self {
Self {
start,
end_exclusive,
step,
}
}
}
impl<T> Iterator for StepBy<T>
where
T: Add<Output = T> + PartialOrd + Copy,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.start < self.end_exclusive {
let v = self.start;
self.start = self.start + self.step;
Some(v)
} else {
None
}
}
}
fn main() {
for i in StepBy::new(0, 100, 2) {
println!("i: {}", i);
}
}
See also:
There is way using let
"redefinition":
for i in 0..((n + 1) / 2) {
let i = i * 2;
// …
}
Or use Iterator::map
:
for i in (0..((n + 1) / 2)).map(|i| i * 2) {
// …
}
You can use the iterator_step_by
feature.
Here is an example of two threads running, one of them printing out odd numbers and the other even ones:
#![feature(iterator_step_by)]
extern crate thebook;
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in (1..1000).step_by(2) {
println!("{}", i);
}
});
for i in (2..1000).step_by(2) {
println!("{}", i);
}
handle.join();
}
Without this feature, you can also use a filter on the range:
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in (1..1000).filter(|x| x % 2 != 0) {
println!("{}", i);
}
});
for i in (2..1000).filter(|x| x % 2 == 0) {
println!("{}", i);
}
handle.join();
}
I think i'll stick to a while loop. But if you really want an iterator based method you could try this
fn main(){
let (start, step, end) = (1, 2, 20);
for i in (0..).map(|x| start+step*x)
.take_while(|&x| x<end){
println!("{:?}", i);
}
}
Use the crate num
Cargo.toml:
[dependencies.num]
version = "0.1.25"
default-features = false
Since you only need the crate's basics, use default-features = false
.
Rust:
extern crate num;
use num::range_step;
for i in range_step(0, 10, 2) {
/* */
}
range_step
is generic over rust's integer types.