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

问题描述 投票:0回答:5

如何使用

1
以外的步骤迭代 Rust 中的某个范围?我有 C++ 背景,所以我想做类似的事情

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

在 Rust 中,我需要使用

range
函数,并且似乎没有第三个参数可用于自定义步骤。我怎样才能做到这一点?

rust iterator
5个回答
315
投票

range_step_inclusive
range_step
早已消失。

从 Rust 1.28 开始,

Iterator::step_by
已稳定:

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

16
投票

在我看来,在

.step_by
方法变得稳定之前,人们可以轻松地用
Iterator
完成你想要的事情(这就是
Range
的真正含义):

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()
调用而损失效率。缺点是需要几行代码来设置迭代器,因此可能只适合具有大量循环的代码。


6
投票

您将编写 C++ 代码:

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

...在 Rust 中就像这样:

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

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


5
投票

如果您正在逐步执行预定义的值,并且像 2 这样小,您可能希望使用迭代器来手动执行。例如:

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();
    }
}

5
投票

使用 num 箱子和 range_step

© www.soinside.com 2019 - 2024. All rights reserved.