rust 如何使用自定义步长在一个范围内进行缩放?

k4ymrczo  于 12个月前  发布在  其他
关注(0)|答案(5)|浏览(113)

我如何在Rust中使用1以外的步骤来遍历一个范围?我来自C++背景,所以我想做一些类似的事情

for(auto i = 0; i <= n; i+=2) {
    //...
}

字符串
在Rust中,我需要使用range函数,并且似乎没有第三个参数可以用于自定义步骤。我如何才能实现这一点?

esyap4oy

esyap4oy1#

range_step_inclusiverange_step早就消失了。
从Rust 1.28开始,Iterator::step_by是稳定的:

fn main() {
    for x in (1..10).step_by(2) {
        println!("{}", x);
    }
}

字符串

muk1a3rh

muk1a3rh2#

在我看来,在.step_by方法稳定之前,人们可以很容易地用Iterator实现你想要的东西(这就是Range s的真正含义):

struct SimpleStepRange(isize, isize, isize);  // start, end, and step

impl Iterator for SimpleStepRange {
    type Item = isize;

    #[inline]
    fn next(&mut self) -> Option<isize> {
        if self.0 < self.1 {
            let v = self.0;
            self.0 = v + self.2;
            Some(v)
        } else {
            None
        }
    }
}

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

字符串
如果需要对不同类型的多个范围进行编译,则可以将代码设置为泛型,如下所示:

use std::ops::Add;

struct StepRange<T>(T, T, T)
    where for<'a> &'a T: Add<&'a T, Output = T>,
          T: PartialOrd,
          T: Clone;

impl<T> Iterator for StepRange<T>
    where for<'a> &'a T: Add<&'a T, Output = T>,
          T: PartialOrd,
          T: Clone
{
    type Item = T;

    #[inline]
    fn next(&mut self) -> Option<T> {
        if self.0 < self.1 {
            let v = self.0.clone();
            self.0 = &v + &self.2;
            Some(v)
        } else {
            None
        }
    }
}

fn main() {
    for i in StepRange(0u64, 10u64, 2u64) {
        println!("{}", i);
    }
}


如果需要一个无限循环,我将把它留给你来消除上限检查,以创建一个开放式结构。
这种方法的优点是它可以与for sugaring一起工作,即使不稳定的特性变得可用,它也会继续工作;而且,与使用标准Range s的去糖方法不同,它不会因为多次.next()调用而降低效率。缺点是它需要几行代码来设置迭代器,所以可能只适合有很多循环的代码。

kiz8lqtg

kiz8lqtg3#

你会写你的C++代码:

for (auto i = 0; i <= n; i += 2) {
    //...
}

字符串
在Rust中是这样的:

let mut i = 0;
while i <= n {
    // ...
    i += 2;
}


我认为Rust版本也更可读。

7d7tgy0s

7d7tgy0s4#

如果你要遍历一些预定义的东西,比如2,你可能希望使用迭代器手动遍历。例如:

let mut iter = 1..10;
loop {
    match iter.next() {
        Some(x) => {
            println!("{}", x);
        },
        None => break,
    }
    iter.next();
}

字符串
你甚至可以用它来步进任意数量(尽管这肯定会变得越来越长,越来越难消化):

let mut iter = 1..10;
let step = 4;
loop {
    match iter.next() {
        Some(x) => {
            println!("{}", x);
        },
        None => break,
    }
    for _ in 0..step-1 {
        iter.next();
    }
}

相关问题