¿Cómo puedo iterar sobre un rango en Rust con un paso que no sea 1? Vengo de una experiencia en C ++, así que me gustaría hacer algo como
for(auto i = 0; i <= n; i+=2) {
//...
}
En Rust necesito usar la range
función, y no parece que haya un tercer argumento disponible para tener un paso personalizado. ¿Cómo puedo lograr esto?
Me parece que hasta que el
.step_by
método se estabilice, uno puede lograr fácilmente lo que desea con unIterator
(que es lo queRange
realmente son de todos modos):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); } }
Si uno necesita iterar múltiples rangos de diferentes tipos, el código puede hacerse genérico de la siguiente manera:
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); } }
Dejaré que usted elimine la verificación de límites superiores para crear una estructura abierta si se requiere un bucle infinito ...
Las ventajas de este enfoque es que funciona con el
for
azúcar y seguirá funcionando incluso cuando las características inestables se vuelvan utilizables; Además, a diferencia del enfoque sin azúcar que usa los estándaresRange
, no pierde eficiencia por múltiples.next()
llamadas. Las desventajas son que se necesitan algunas líneas de código para configurar el iterador, por lo que solo puede valer la pena para el código que tiene muchos bucles.fuente
U
a su segunda opción puede usar tipos que admitan la adición con un tipo diferente y aún así producir unT
. Por ejemplo, me vienen a la mente el tiempo y la duración.Usa la caja num con range_step
fuente
Escribirías tu código C ++:
for (auto i = 0; i <= n; i += 2) { //... }
... en Rust así:
let mut i = 0; while i <= n { // ... i += 2; }
Creo que la versión de Rust también es más legible.
fuente
continue
funcione correctamente. Aunque se puede hacer, este diseño fomenta los errores.Si está pasando por algo predefinido y pequeño como 2, es posible que desee utilizar el iterador para avanzar manualmente. p.ej:
let mut iter = 1..10; loop { match iter.next() { Some(x) => { println!("{}", x); }, None => break, } iter.next(); }
Incluso podría usar esto para pasar por una cantidad arbitraria (aunque definitivamente esto se está volviendo más largo y más difícil de digerir):
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(); } }
fuente