Iteradores

El rasgo Iterator se usa para implementar iteradores sobre colecciones como matrices.

El rasgo solo requiere que se defina un método para el elemento next, que puede definirse manualmente en un bloque impl o definirse automáticamente (como en matrices y rangos).

Como punto de conveniencia para situaciones comunes, la construcción for convierte algunas colecciones en iteradores usando el método .into_iter().

struct Fibonacci {
    actual: u32,
    siguiente: u32,
}

// Implementa `Iterator` para` Fibonacci`.
// El rasgo `Iterator` solo requiere que se defina un método para el elemento `next`.
impl Iterator for Fibonacci {
    // Podemos referirnos a este tipo usando Self::Item
    type Item = u32;
    
    // Aquí, definimos la secuencia usando `.actual` y `.siguiente`.
    // El tipo de retorno es `Option<T>`:
    // * Cuando finaliza el `Iterator`, se devuelve `None`.
    // * De lo contrario, el valor siguiente se envuelve en `Some` y se devuelve.
    // Usamos Self::Item en el tipo de retorno, por lo que podemos cambiar el tipo sin
    // tener que actualizar las signaturas de la función.
    fn next(&mut self) -> Option<Self::Item> {
        let nuevo_siguiente = self.actual + self.siguiente;

        self.actual = self.siguiente;
        self.siguiente = nuevo_siguiente;

        // Dado que no hay un punto final para una secuencia de Fibonacci, el `Iterator`
        // nunca devolverá `None`, y siempre se devuelve `Some`.
        Some(self.actual)
    }
}

// Devuelve un generador de secuencia de Fibonacci
fn fibonacci() -> Fibonacci {
    Fibonacci { actual: 0, siguiente: 1 }
}

fn main() {
    // `0..3` es in `Iterator` que genera: 0, 1, y 2.
    let mut secuencia = 0..3;

    println!("Cuatro llamadas `siguiente` consecutivas en 0..3");
    println!("> {:?}", secuencia.next());
    println!("> {:?}", secuencia.next());
    println!("> {:?}", secuencia.next());
    println!("> {:?}", secuencia.next());

    // `for` funciona a través de un `Iterator` hasta que devuelve `None`.
    // Cada valor de `Some` se desenvuelve y se vincula a una variable (aquí, `i`).
    println!("Itera a través de 0..3 usando `for`");
    for i in 0..3 {
        println!("> {}", i);
    }

    // El método `take(n)` reduce un `Iterator` a sus primeros `n` elementos.
    println!("Los primeros cuatro términos de la secuencia de Fibonacci son: ");
    for i in fibonacci().take(4) {
        println!("> {}", i);
    }

    // El método `skip(n)` acorta un `Iterator` eliminando sus primeros `n` elementos.
    println!("Los siguientes cuatro términos de la secuencia de fibonacci son:: ");
    for i in fibonacci().skip(4).take(4) {
        println!("> {}", i);
    }

    let array = [1u32, 3, 3, 7];

    // El método `iter` produce un `Iterator` sobre una matriz/segmento.
    println!("Itera la siguiente matriz: {:?}", &array);
    for i in array.iter() {
        println!("> {}", i);
    }
}