Как выполнить итерацию по диапазону с помощью настраиваемого шага?
Как я могу перебирать диапазон в Rust с шагом, отличным от 1? Я исхожу из фона С++, поэтому я хотел бы сделать что-то вроде
for(auto i = 0; i <= n; i+=2) {
//...
}
В Rust мне нужно использовать функцию range
, и, похоже, нет третьего аргумента, доступного для пользовательского шага. Как я могу это сделать?
Ответы
Ответ 1
range_step_inclusive
и range_step
, похоже, давно прошли. В ночное время существует нестабильный метод Iterator::step_by
, который можно использовать следующим образом:
#![feature(iterator_step_by)]
fn main() {
for x in (1..10).step_by(2) {
println!("{}", x);
}
}
Ответ 2
Мне кажется, что до тех пор, пока метод .step_by
не станет стабильным, можно легко выполнить то, что вы хотите, с помощью Iterator
(что в любом случае Range
):
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
сахарированием и будет продолжать работать, даже когда неустойчивые функции станут полезными; Кроме того, в отличие от подхода de-sugared, использующего стандартный Range
s, он не теряет эффективности несколькими вызовами .next()
. Недостатки в том, что для создания итератора требуется несколько строк кода, поэтому может стоить только для кода с большим количеством циклов.
Ответ 3
Вы напишете свой код на С++:
for (auto i = 0; i <= n; i += 2) {
//...
}
... в Rust вот так:
let mut i = 0;
while i <= n {
// ...
i += 2;
}
Я думаю, что версия Rust более читаема.
Ответ 4
Если вы шагнули на что-то предопределенное и небольшое, как 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();
}
}
Ответ 5
Используйте num ящик с range_step