【问题标题】:Is there a way to do a for loop that is neither iterative nor linear?有没有办法做一个既不是迭代也不是线性的 for 循环?
【发布时间】:2018-02-28 13:20:02
【问题描述】:

我可以写一个 Rust for 循环等效于这个 C 代码吗:

for(int i = 2; i <= 128; i=i*i){
    //do something
}

我只看到类似的东西

for i in 0..128 { /* do something */ }

或

let v = vec![0, 1, 2, /* ... */ ];
for i in v.iter() { /* do something */ }

我应该只使用while 循环吗?

【问题讨论】:

标签: for-loop rust


【解决方案1】:

您可以始终创建一个自定义迭代器来执行您需要的任何唯一序列:

struct Doubling {
    current: u64,
    max: u64,
}

impl Iterator for Doubling {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current > self.max {
            None
        } else {
            let v = Some(self.current);
            self.current *= 2;
            v
        }
    }
}

fn main() {
    let iter = Doubling { current: 2, max: 128 };
    let values: Vec<_> = iter.collect();
    println!("{:?}", values);
}

当值加倍超出类型大小时,必须认识到这种逻辑(就像原始 C 语言一样!)具有令人讨厌的边缘情况。


在这个特殊的案例中,你也可以认识到你有一个指数级数:

fn main() {
    let iter = (1..8).map(|p| 2i32.pow(p));
    let values: Vec<_> = iter.collect();
    println!("{:?}", values);
}

如果您想进行真正的实验,请查看Lazy sequence generation in Rust。在此改编:

#![feature(generators, generator_trait, conservative_impl_trait)]

use std::ops::{Generator, GeneratorState};

fn doubling(mut start: u64, max: u64) -> impl Iterator<Item = u64> {
    GeneratorIteratorAdapter(move || {
        while start <= max {
            yield start;
            start *= 2;
        }
    })
}

fn main() {
    let iter = doubling(2, 128);
    let sum: Vec<_> = iter.collect();
    println!("{:?}", sum);
}

/* copy-pasta */
struct GeneratorIteratorAdapter<G>(G);

impl<G> Iterator for GeneratorIteratorAdapter<G>
where
    G: Generator<Return = ()>,
{
    type Item = G::Yield;

    fn next(&mut self) -> Option<Self::Item> {
        match self.0.resume() {
            GeneratorState::Yielded(x) => Some(x),
            GeneratorState::Complete(_) => None,
        }
    }
}

【讨论】:

  • 我的意思是...是的,但这并不能完全帮助 Rust 获得冗长的声誉。这是“使用死亡之星炸毁星球杀死蜘蛛”的过度杀伤力......
  • 查看最新编辑 好的,现在你是故意这样做的。 :P
  • @DK。我的意思是,只有一点点;-)。但是,正如我在链接问题中提到的那样,我认为 GeneratorIteratorAdapter 将以 some 形式成为标准库的一部分,而 doubling 函数“合理”地很小。
【解决方案2】:

我可以写一个等效于这个 C 代码的 for 循环吗:

具体来说,是的:

extern crate itertools;
for i in itertools::iterate(2, |&i| i*i).take_while(|&i| i <= 128) {
    // do something
}

但总的来说,不会。没有单一的 direct 等效于 C 的 for 循环的所有可能用途。如果没有办法使用迭代器编写它,那么是的,您需要使用更通用的循环形式:

{
    let mut i = 2;
    while i <= 128 {
        // do something
        i = i*i;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-12-14
    • 2019-12-23
    • 1970-01-01
    • 1970-01-01
    • 2019-06-17
    • 2020-08-11
    • 2021-11-15
    • 1970-01-01
    相关资源
    最近更新 更多