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

时间:2015-07-12 19:04:05

标签: iterator rust

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

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

}

我已尝试使用range_step_inclusiveHow do I iterate over a range with a custom step?中的解决方案:

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

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

error: unresolved import `std::iter::range_step_inclusive`. There is no `range_step_inclusive` in `std::iter`

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

6 个答案:

答案 0 :(得分:6)

Rust 1.28 +

Iterator::step_by现在稳定了:

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

Rust 1.1 +

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

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

然后可以抽象出来:

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

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

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

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

另见:

答案 1 :(得分:5)

可以使用let&#34;重新定义&#34;:

for i in 0..((n + 1) / 2) {
    let i = i * 2;
    // …
}

或使用Iterator::map

for i in (0..((n + 1) / 2)).map(|i| i * 2) {
    // …
}

答案 2 :(得分:3)

我想我会坚持一个循环。但是如果你真的想要一个基于迭代器的方法,你可以试试这个

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

答案 3 :(得分:3)

使用crate num

Cargo.toml:

[dependencies.num]
version = "0.1.25"
default-features = false

由于您只需要条件箱的基础知识,因此请使用default-features = false

锈:

extern crate num;

use num::range_step;

for i in range_step(0, 10, 2) {
    /*    */
}

range_step对于rust的整数类型是通用的。

答案 4 :(得分:1)

自从问了这个问题以来,itertools crate就已经成为相当标准的依赖项。您可以使用step()方法非常简单地完成所需的操作:

extern crate itertools; // 0.7.8
use itertools::Itertools;

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

在您的Cargo.toml中:

[dependencies]
itertools = "0.7.8"

答案 5 :(得分:-1)

您可以使用iterator_step_by功能。

以下是两个线程运行的示例,其中一个线程打印出奇数,另一个打印出奇数:

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

如果没有此功能,您还可以在范围内使用过滤器:

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