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

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

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

在 Rust 中,我需要使用 range函数,而且似乎没有第三个参数可用于定制步骤。我该怎么做呢?

90198 次浏览

range_step_inclusiverange_step早就没了。

在 Rust 1.28中,Iterator::step_by是稳定的:

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

如果您正在单步执行某个预定义的内容(比如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();
}
}

你可以编写你的 C + + 代码:

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

就像这样:

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

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

在我看来,除非 .step_by方法变得稳定,否则使用 Iterator可以很容易地完成您想要的任务(无论如何,Range就是 Iterator) :

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()调用而失去效率。缺点是需要几行代码来设置迭代器,所以对于有很多循环的代码来说可能只值得这样做。

范围 _ 步长范围 _ 步长一起使用 Num板条箱