Jak mogę iterować zakres w Rust z krokiem innym niż 1? Pochodzę z C ++, więc chciałbym zrobić coś takiego
for(auto i = 0; i <= n; i+=2) {
//...
}
W Rust muszę użyć tej range
funkcji i nie wygląda na to, że jest dostępny trzeci argument za niestandardowym krokiem. Jak mogę to osiągnąć?
Wydaje mi się, że dopóki
.step_by
metoda nie zostanie ustabilizowana, można łatwo osiągnąć to, co chcesz, za pomocąIterator
(coRange
i tak jest tak naprawdę):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); } }
Jeśli trzeba iterować wiele zakresów różnych typów, kod można uczynić generycznym w następujący sposób:
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); } }
Zostawię to tobie, aby wyeliminować sprawdzanie górnych granic, aby utworzyć otwartą strukturę, jeśli wymagana jest nieskończona pętla ...
Zaletą tego podejścia jest to, że działa z
for
cukrowaniem i będzie działać nawet wtedy, gdy niestabilne funkcje staną się użyteczne; ponadto, w przeciwieństwie do metody pozbawionej cukru, używającej standardowychRange
, nie traci wydajności przez wielokrotne.next()
wywołania. Wadą jest to, że skonfigurowanie iteratora zajmuje kilka wierszy kodu, więc może być tego warte tylko w przypadku kodu, który ma dużo pętli.źródło
U
do drugiej opcji możesz użyć typów, które obsługują dodawanie z innym typem i nadal dają plikT
. Na przykład przychodzą na myśl czas i trwanie.Napisałbyś swój kod w C ++:
for (auto i = 0; i <= n; i += 2) { //... }
... w Rust tak:
let mut i = 0; while i <= n { // ... i += 2; }
Myślę, że wersja Rusta też jest bardziej czytelna.
źródło
continue
, aby działała poprawnie. Chociaż można to zrobić, ten projekt zachęca do błędów.Użyj num crate z range_step
źródło
Jeśli przechodzisz przez coś wstępnie zdefiniowanego i małego, jak 2, możesz chcieć użyć iteratora do ręcznego przechodzenia. na przykład:
let mut iter = 1..10; loop { match iter.next() { Some(x) => { println!("{}", x); }, None => break, } iter.next(); }
Możesz nawet użyć tego, aby przejść o dowolną kwotę (chociaż jest to zdecydowanie dłuższe i trudniejsze do strawienia):
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(); } }
źródło