使用自定义步骤迭代范围的稳定方法是什么?

Sos*_*doc 10 iterator rust

如果我想在稳定的Rust中使用自定义步骤进行迭代,我该怎么办?基本上就像C/C++

for (int i = 0; i < n; i += 2) {

}
Run Code Online (Sandbox Code Playgroud)

我已经尝试过使用range_step_inclusive和解决方案如何使用自定义步骤迭代范围?:

use std::iter::range_step_inclusive;
for i in range_step_inclusive(0, n, 2) {
    println!("i: {}", i);
}
Run Code Online (Sandbox Code Playgroud)

但似乎它在Rust 1.1中不可用:

error: unresolved import `std::iter::range_step_inclusive`. There is no `range_step_inclusive` in `std::iter`
Run Code Online (Sandbox Code Playgroud)

什么是另类?可能是创建自定义范围的惯用方法.

She*_*ter 7

Rust 1.28+

Iterator::step_by 现在稳定了:

fn main() {
    for i in (0..100).step_by(2) {
        println!("{}", i);
    }
}
Run Code Online (Sandbox Code Playgroud)

Rust 1.1+

你总是可以用老式的方式写出来:

fn main() {
    let mut i = 0;
    while i < 100 {
        println!("i: {}", i);
        i += 2;
    }
}
Run Code Online (Sandbox Code Playgroud)

然后可以抽象出来:

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);
    })
}
Run Code Online (Sandbox Code Playgroud)

有趣的历史旁注,我相信在迭代器变得极为普遍之前,最初所有的循环都是用这样的闭包完成的.

然后你可以把它变成迭代器:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

也可以看看:


Hau*_*eth 5

有使用let"重新定义"的方法:

for i in 0..((n + 1) / 2) {
    let i = i * 2;
    // …
}
Run Code Online (Sandbox Code Playgroud)

或使用Iterator::map:

for i in (0..((n + 1) / 2)).map(|i| i * 2) {
    // …
}
Run Code Online (Sandbox Code Playgroud)

  • 我认为如果由于四舍五入而n为奇数,这将使最后一个索引缩短.如果n = 5,(n/2)= 2,那么你将在0..2中使用i,并且迭代器不包括在内.这只会在内循环中提供i = 0,i = 2,你将会缺少i = 4,因为C样式循环会提供. (2认同)