如何使用自定义步骤迭代范围?

时间:2015-01-11 23:14:59

标签: rust

如何使用1以外的步骤迭代Rust中的范围?我来自C ++背景,所以我想做一些像

这样的事情
for(auto i = 0; i <= n; i+=2) {
    //...
}

在Rust中我需要使用range函数,并且看起来没有第三个参数可用于自定义步骤。我怎么能做到这一点?

5 个答案:

答案 0 :(得分:58)

range_step_inclusiverange_step早已不复存在。

从Rust 1.28开始,Iterator::step_by是稳定的:

fn main() {
    for x in (1..10).step_by(2) {
        println!("{}", x);
    }
}

答案 1 :(得分:9)

在我看来,在.step_by方法稳定之前,可以使用Iterator轻松完成您想要的任务(无论如何Range确实是这样的):< / p>

struct SimpleStepRange(isize, isize, isize);  // start, end, and step

impl Iterator for SimpleStepRange {
    type Item = isize;

    #[inline]
    fn next(&mut self) -> Option<isize> {
        if self.0 < self.1 {
            let v = self.0;
            self.0 = v + self.2;
            Some(v)
        } else {
            None
        }
    }
}

fn main() {
    for i in SimpleStepRange(0, 10, 2) {
        println!("{}", i);
    }
}

如果需要迭代不同类型的多个范围,可以按如下方式对代码进行通用:

use std::ops::Add;

struct StepRange<T>(T, T, T)
    where for<'a> &'a T: Add<&'a T, Output = T>,
          T: PartialOrd,
          T: Clone;

impl<T> Iterator for StepRange<T>
    where for<'a> &'a T: Add<&'a T, Output = T>,
          T: PartialOrd,
          T: Clone
{
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> {
        if self.0 < self.1 {
            let v = self.0.clone();
            self.0 = &v + &self.2;
            Some(v)
        } else {
            None
        }
    }
}

fn main() {
    for i in StepRange(0u64, 10u64, 2u64) {
        println!("{}", i);
    }
}

如果需要无限循环,我会留给你消除上界检查以创建一个开放式结构......

这种方法的优点是可以使用for加糖,并且即使在不稳定的特征变得可用时也会继续工作;此外,与使用标准Range的去糖方法不同,它不会因多个.next()调用而失去效率。缺点是需要几行代码来设置迭代器,因此对于具有大量循环的代码来说可能是值得的。

答案 2 :(得分:3)

你要编写C ++代码:

for (auto i = 0; i <= n; i += 2) {
    //...
}

...在Rust中如此:

let mut i = 0;
while i <= n {
    // ...
    i += 2;
}

我认为Rust版本更具可读性。

答案 3 :(得分:3)

num crate与range_step

一起使用

答案 4 :(得分:1)

如果您正在踩踏预定义的东西,并且像2那样小,您可能希望使用迭代器手动步进。 e.g:

let mut iter = 1..10;
loop {
    match iter.next() {
        Some(x) => {
            println!("{}", x);
        },
        None => break,
    }
    iter.next();
}

您甚至可以使用此步骤任意数量(虽然这肯定会变得更长,更难消化):

let mut iter = 1..10;
let step = 4;
loop {
    match iter.next() {
        Some(x) => {
            println!("{}", x);
        },
        None => break,
    }
    for _ in 0..step-1 {
        iter.next();
    }
}