What is a stable way to iterate on a range with custom step?

前端 未结 6 884
不思量自难忘°
不思量自难忘° 2021-01-01 18:41

How should I go if I want to iterate with a custom step in stable Rust? Essentially something like the C/C++

for (in         


        
相关标签:
6条回答
  • 2021-01-01 19:13

    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"
    
    0 讨论(0)
  • 2021-01-01 19:25

    Rust 1.28+

    Iterator::step_by is now stable:

    fn main() {
        for i in (0..100).step_by(2) {
            println!("{}", i);
        }
    }
    

    Rust 1.1+

    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:

    • How can I add new methods to Iterator?
    0 讨论(0)
  • 2021-01-01 19:26

    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) {
        // …
    }
    
    0 讨论(0)
  • 2021-01-01 19:27

    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();
    }
    
    0 讨论(0)
  • 2021-01-01 19:34

    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);
        }
    }
    
    0 讨论(0)
  • 2021-01-01 19:38

    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.

    0 讨论(0)
提交回复
热议问题