是否可以在不创建特殊迭代器的情况下每次迭代增加不同的数量? [英] Is it possible to step by a different amount each iteration without creating a special iterator?

查看:106
本文介绍了是否可以在不创建特殊迭代器的情况下每次迭代增加不同的数量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在C语言中,一个for循环具有一个可选的递增部分,我有时在Rust中会错过它:

In C, a for loop has an optional increment section which I sometimes miss in Rust:

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

这可以用Rust编写为:

This could be written in Rust as:

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

...但是,如果continue存在于许多代码行" 中的某处,则会引入错误.我个人的喜好也是将增量保持在循环的顶部.

... however this will introduce bugs if continue exists somewhere in the "many lines of code". My personal preference is also to keep the increment at the top of the loop.

无需创建特殊的迭代器来处理此问题,是否有一种方法可以使循环更紧密地匹配C样式,从而解决上述两个问题?

Without creating a special iterator to handle this, is there a way to loop that matches C style more closely, accounting for both issues mentioned?

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

By "special iterator", I mean not having to define an iterator type and methods outside the for loop.

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

While it may seem like an artificial requirement, having to define an iterator for a single use - adds some overhead both in reading and writing the code.

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

Although @kennytm's answer shows how a reusable StepByFn iterator could work, using closures adds some constraints to the code that wouldn't exist otherwise.

推荐答案

如果可以导入外部包装箱,则应使用

If you could import an external crate, you should use 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样式的for循环,则可以使用 cfor 板条箱:


And if you are really missing the C-style for loop, you could use the cfor crate:

#[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
    }}
}


如果仅限于使用标准库,那么创建特殊的迭代器将是最惯用的方式.


If you are restricting to using the standard library only, creating a special iterator would be the most idiomatic way.

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()创建内联迭代器,但是它非常难看并且不能很好地表达意图

It is also possible to create an inline iterator with repeat().scan(), but it is very ugly and does not express the intention very well

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

这篇关于是否可以在不创建特殊迭代器的情况下每次迭代增加不同的数量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆