Как я могу перебрать диапазон в Rust с шагом, отличным от 1? Я работаю с C ++, поэтому я хотел бы сделать что-нибудь вроде
for(auto i = 0; i <= n; i+=2) {
//...
}
В Rust мне нужно использовать эту range
функцию, и не похоже, что есть третий аргумент для использования настраиваемого шага. Как я могу этого добиться?
Мне кажется, что до тех пор, пока
.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
шугарингом и будет продолжать работать, даже когда нестабильные функции станут доступны для использования; Кроме того, в отличие от подхода без сахара, использующего стандартныеRange
s, он не теряет эффективности из-за нескольких.next()
вызовов. Недостатки заключаются в том, что для настройки итератора требуется несколько строк кода, поэтому оно может иметь смысл только для кода с большим количеством циклов.источник
U
ко второму варианту, вы можете использовать типы, которые поддерживают добавление с другим типом и по-прежнему даютT
. Например, на ум приходят время и продолжительность.Используйте num crate с range_step
источник
Вы бы написали свой код на C ++:
for (auto i = 0; i <= n; i += 2) { //... }
... в Rust вот так:
let mut i = 0; while i <= n { // ... i += 2; }
Я думаю, что версия на Rust тоже более читабельна.
источник
continue
, чтобы она работала правильно. Хотя это возможно, такая конструкция поощряет ошибки.Если вы переходите по заранее заданному параметру, например, маленькому, например 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(); } }
источник