Loops 是否有可能在不创建特殊迭代器的情况下,在每次迭代中逐步增加不同的量?

Loops 是否有可能在不创建特殊迭代器的情况下,在每次迭代中逐步增加不同的量?,loops,rust,control-flow,Loops,Rust,Control Flow,在C中,for循环有一个可选的增量部分,我在Rust中有时会忽略它: for (uint i = 0; i < max; i = step_function(i, j, k)) { /* many lines of code! */ } for(uint i=0;i

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

for (uint i = 0; i < max; i = step_function(i, j, k)) {
    /* many lines of code! */
}
for(uint i=0;i
这可以用铁锈书写为:

let mut i: u32 = 0;
while (i < max) {
    // 
    // many lines of code! 
    //
    i = step_function(i, j, k);
}
设mut i:u32=0;
而(i
。。。但是,如果“多行代码”中存在
continue
,则会引入错误。我个人的偏好也是将增量保持在循环的顶部

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

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

虽然这看起来像是一个人工需求,但必须为一次使用定义一个迭代器,这会在读写代码时增加一些开销


尽管@kennytm的回答显示了可重用的
StepByFn
迭代器是如何工作的,但使用闭包会给代码添加一些其他情况下不存在的约束。

如果可以导入外部板条箱,则应使用:


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

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

我不确定这是否真的是一个骗局,但给了你答案。还有相关的。这个例子没有使用自定义步长,它是通过一个任意函数步进的,这使得上面的例子没有那么紧密的联系。(
step_by
不能用于替换
step_函数
在此处的用法)。您需要什么样的约束,而闭包无法覆盖?i、 e.你有什么具体的例子吗?@kennytm,来自过去使用闭包——在块体中可以使用一些表达式,这些表达式会在闭包中产生错误。毫无疑问,有很多方法可以解决大多数情况,但是这使得移植代码的过程不那么简单。因此,询问是否可以使用C型循环。当然,使用宏(即
cfor
板条箱)有其利弊,因此需要对解决方案进行加权-也许为了获得C代码的初始端口,使用
cfor
宏是有意义的,例如,以后可以使代码更粗糙(一旦测试到位)。虽然我同意您回答的内容,我不相信这回答了OP所要求的限制问题:不创建特殊的迭代器。此外,由于OP未明确说明问题,
j
k
可能在循环内部计算(甚至可能来自外部源)。这里提供的所有解决方案都要求在开始循环之前知道迭代的次数。@Shepmaster① 如果
iterate()。(顺便说一句,这对未来的读者应该更有帮助。)② 重新计算
j
k
意味着将它们设为
单元格
。我将等待OP的澄清。③ 我不明白你所说的“关于迭代多少的信息”是什么意思。这对未来的读者应该更有帮助——我完全同意。我只是指出了OP中的细微差别。我真的不知道简单地实例化迭代器是否满足这些限制。关于迭代多少的信息是我试图抽象“所有进入闭包的东西”。在您的示例中,这将是
2*i+3
,但外部数据和朋友可能会带来复杂性。@Shepmaster我明白了,谢谢。如果
step_函数
足够简单(即它不依赖于需要在循环内重新计算的
j
k
),那么当前方法就足够了。太糟糕了
scopeguard::defer在这里不起作用:(@Shepmaster:指定“不使用迭代器”是一个X/Y问题。让OP暴露问题,答案提出解决方案。限制“不使用分号”、“不使用大括号”或“不创建自定义迭代器”?为什么?我们没有。
#[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)
    }
}
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
    }
}