是否可以在不创建特殊迭代器的情况下每次迭代步进不同的量?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了是否可以在不创建特殊迭代器的情况下每次迭代步进不同的量?相关的知识,希望对你有一定的参考价值。

在C中,for循环有一个可选的增量部分,我有时会在Rust中错过:

for (uint i = 0; i < max; i = step_function(i, j, k)) {
    /* many lines of code! */
}

这可以用Rust写成:

let mut i: u32 = 0;
while (i < max) {
    // 
    // many lines of code! 
    //
    i = step_function(i, j, k);
}

...但是如果continue存在于“多行代码”的某个地方,这将引入错误。我个人的偏好也是将增量保持在循环的顶部。

如果没有创建一个特殊的迭代器来处理这个问题,有没有一种方法可以更紧密地匹配C风格,同时解决了上述两个问题?

通过“特殊迭代器”,我的意思是不必在for循环之外定义迭代器类型和方法。

虽然它似乎是一个人为的要求,但必须为一次使用定义一个迭代器 - 在读取和编写代码时增加了一些开销。

尽管@ kennytm的答案显示了可重用的StepByFn迭代器如何工作,但使用闭包会为代码增加一些限制,否则将不存在。

答案

如果你可以导入外部包,你应该使用itertools::iterate

extern crate itertools;
use itertools::iterate;

fn main() {
    for i in iterate(0, |i| 2*i + 3).take_while(|i| *i < 100) {
        println!("{}", i);
        // 0 3 9 21 45 93
    }
}

如果你真的错过了C风格的循环,你可以使用cfor箱子:

#[macro_use] extern crate cfor;

fn main() {
    cfor!{ let mut i = 0; i < 100; i = 2*i + 3; {
        println!("{}", i);
        // 0 3 9 21 45 93
    }}
}

如果您只限制使用标准库,那么创建一个特殊的迭代器将是最惯用的方式。

fn main() {
    for i in StepByFn::new(0, 100, |i| 2*i + 3) {
        println!("{}", i);
        // 0 3 9 21 45 93
    }
}

struct StepByFn<T, F> {
    begin: T,
    end: T,
    step: F,
}

impl<T, F: FnMut(&T) -> T> StepByFn<T, F> {
    pub fn new(begin: T, end: T, step: F) -> StepByFn<T, F> {
        StepByFn { begin, end, step }
    }
}

impl<T: PartialOrd, F: FnMut(&T) -> T> Iterator for StepByFn<T, F> {
    type Item = T;
    fn next(&mut self) -> Option<T> {
        if self.begin >= self.end {
            return None;
        }
        let next = (self.step)(&self.begin);
        let prev = std::mem::replace(&mut self.begin, next);
        Some(prev)
    }
}

也可以使用repeat().scan()创建一个内联迭代器,但它非常难看并且不能很好地表达意图

use std::iter::repeat;

fn main() {
    for i in repeat(()).scan(0, |i, ()| { 
        let old = *i; 
        *i = 2*old + 3; 
        if old < 100 { Some(old) } else { None } 
    }) {
        println!("{}", i);
        // 0 3 9 21 45 93
    }
}

以上是关于是否可以在不创建特殊迭代器的情况下每次迭代步进不同的量?的主要内容,如果未能解决你的问题,请参考以下文章

使用带有迭代器的 boost 字符串算法

是否可以在不使用文本包装器的情况下使用不同的列表编号字体大小和列表内部文本? [复制]

如何在不创建临时对象的情况下迭代嵌套的 TreeMap

使用 Spring Data Mongodb,是不是可以在不拉取和迭代整个集合的情况下获得字段的最大值?

NHibernate 可以在没有迭代器的情况下保存集合吗?

是否有用于从 julia 中的类似生成器的函数创建快速迭代器的宏?