【发布时间】:2015-03-09 16:50:45
【问题描述】:
如何在 Rust 中以 1 以外的步骤迭代一个范围?我来自 C++ 背景,所以我想做类似的事情
for(auto i = 0; i <= n; i+=2) {
//...
}
在 Rust 中,我需要使用 range 函数,而且似乎没有第三个参数可用于自定义步骤。我怎样才能做到这一点?
【问题讨论】:
标签: rust
如何在 Rust 中以 1 以外的步骤迭代一个范围?我来自 C++ 背景,所以我想做类似的事情
for(auto i = 0; i <= n; i+=2) {
//...
}
在 Rust 中,我需要使用 range 函数,而且似乎没有第三个参数可用于自定义步骤。我怎样才能做到这一点?
【问题讨论】:
标签: rust
range_step_inclusive 和 range_step 早已不复存在。
从 Rust 1.28 开始,Iterator::step_by 是稳定的:
fn main() {
for x in (1..10).step_by(2) {
println!("{}", x);
}
}
【讨论】:
(11..=1).step_by(-2)(奇数从11倒数到1,包括),你必须做(1..12).step_by(2).rev(),这不是很直观。
在我看来,在.step_by 方法稳定之前,使用Iterator 可以轻松完成您想要的(无论如何Ranges 确实如此):
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 加糖,即使在不稳定的功能变得可用时也能继续工作;此外,与使用标准Ranges 的脱糖方法不同,它不会因多次.next() 调用而降低效率。缺点是需要几行代码来设置迭代器,所以可能只对有很多循环的代码才值得。
【讨论】:
U 添加到您的第二个选项中,您可以使用支持添加不同类型的类型,并且仍然产生 T。例如时间和持续时间。
你会编写你的 C++ 代码:
for (auto i = 0; i <= n; i += 2) {
//...
}
...在 Rust 中是这样的:
let mut i = 0;
while i <= n {
// ...
i += 2;
}
我认为 Rust 版本也更具可读性。
【讨论】:
continue 正常工作是违反直觉的忙碌工作。虽然可以做到,但这种设计鼓励了错误。
将num 与range_step 一起使用
【讨论】:
如果您正在按预定义的内容进行步进,并且像 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();
}
}
【讨论】:
for 和step_by 上使用这个?