Curso de choque de óxido. Iteradores

A continuación se muestra una traducción de una de las partes de la serie de artículos del curso Rust Crash de Michael Snoiman sobre iteradores. El material me pareció exitoso en términos de accesibilidad, así que decidí publicar la traducción que hice para mí. Espero que sea útil para alguien. Si este material es interesante, publicaré algunas traducciones más de esta serie.







También traté de traducir lo más cerca posible del estilo del autor, pero reduje algunos interdomos y exclamaciones que no son muy significativas para el significado.







¡Más iteradores!



Por mi parte, he descubierto que la forma más fácil de entender cómo funcionan los iteradores es escribir algunos de ellos yo mismo, así que ahí es donde comenzamos.







Hagamos programación guiada por el compilador. Discutimos anteriormente que hay un rasgo Iterator



. Así que apuesto a que necesitamos crear un nuevo tipo de datos y proporcionar una implementación para este rasgo. Comencemos con algo simple, un iterador que no produce ningún valor.







struct Empty;

fn main() {
    for i in Empty {
        panic!("Wait, this shouldn't happen!");
    }
    println!("All done!");
}
      
      





Panic ( panic!()



) es una forma de terminar el hilo actual cuando ocurre una situación imposible. Esto es similar a las excepciones en tiempo de ejecución en otros idiomas, excepto que no se puede recuperar. Por lo tanto, solo debe usarse para tales situaciones.







Compilemos esto y obtengamos un mensaje de error útil:







error[E0277]: `Empty` is not an iterator
 --> src/main.rs:5:14
  |
5 |     for i in Empty {
  |              ^^^^^ `Empty` is not an iterator
  |
  = help: the trait `std::iter::Iterator` is not implemented for `Empty`
  = note: required by `std::iter::IntoIterator::into_iter`
      
      





Agreguemos una implementación vacía:







impl Iterator for Empty {
}
      
      





:







error[E0046]: not all trait items implemented, missing: `Item`, `next`
 --> src/main.rs:4:1
  |
4 | impl Iterator for Empty {
  | ^^^^^^^^^^^^^^^^^^^^^^^ missing `Item`, `next` in implementation
  |
  = help: implement the missing item: `type Item = Type;`
  = help: implement the missing item: `fn next(&mut self) -> std::option::Option<<Self as std::iter::Iterator>::Item> { todo!() }`
      
      





, : Item



next()



, , . type Item



? , (associated type). , . , . u32



:







struct Empty;

impl Iterator for Empty {
    type Item = u32;
}
      
      





- next



. :







fn(&mut Self) -> std::option::Option<<Self as std::iter::Iterator>::Item>
      
      





. — &mut Self



. , &mut self



. ? , &mut self



self: &mut Self



.







fn(&mut self) -> std::option::Option<<Self as std::iter::Iterator>::Item>
      
      





Option



Iterator



, (namespace):







fn(&mut self) -> Option<<Self as Iterator>::Item>
      
      





Self as Iterator



: " Iterator



". , , — ::Item



. , , " Item



, Iterator



". , , .







, ? :







struct Empty;

impl Iterator for Empty {
    type Item = u32;

    fn next(&mut self) -> Option<<Self as Iterator>::Item> {
        unimplemented!()
    }
}
      
      





unimplemented!()



— , panic!()



. , . () unimplemented!()



.







, as Iterator



, :







fn next(&mut self) -> Option<Self::Item>
      
      





, Self::Item



u32



. — , , Item



, . .







. Option



, (enum



) : None



Some



. " ", — " -". , , None



, :







struct Empty;

impl Iterator for Empty {
    type item = u32;
    fn next(&mut self) -> Option<u32> {
        None
    }
}
      
      





Iterator



.









, 42



. main



.







fn main() {
    // only take 10 to avoid looping forever
    for i in TheAnswer.take(10) {
        println!("The answer to life, the universe, and everything is {}", i);
    }
    println!("All done!");
}
      
      





struct TheAnswer;

impl Iterator for TheAnswer {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        Some(42)
    }
}
      
      







next



self



. ! , 1 10. ( , , , ).







struct OneToTen(u32);

fn one_to_ten() -> OneToTen {
    OneToTen(1)
}

impl Iterator for OneToTen {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        if self.0 > 10 {
            None
        } else {
            let res = Some(self.0);
            self.0 += 1;
            res
        }
    }
}

fn main() {
    for i in one_to_ten() {
        println!("{}", i);
    }
}
      
      







, .







Comencemos con la solución más simple.







struct Fibs {
    x: u32,
    y: u32,
}

fn fibs() -> Fibs {
    Fibs {
        x: 0,
        y: 1,
    }
}

impl Iterator for Fibs {
    type Item = u32;

    fn next(&mut self) -> Option<u32> {
        let orig_x = self.x;
        let orig_y = self.y;

        self.x = orig_y;
        self.y = orig_x + orig_y;

        Some(orig_x)
    }
}

fn main() {
    for i in fibs().take(10) {
        println!("{}", i);
    }
}
      
      





, take(10)



take(47)



, :







701408733
1134903170
thread 'main' panicked at 'attempt to add with overflow', foo.rs:21:18
note: Run with `RUST_BACKTRACE=1` for a backtrace.
      
      





u64



, . :







fn next(&mut self) -> Option<u32> {
    let orig_x = self.x;
    let orig_y = self.y;

    match orig_x.checked_add(orig_y) {
        // overflow
        None => None,

        // no overflow
        Some(new_y) => {
            self.x = orig_y;
            self.y = new_y;

            Some(orig_x)
        }
    }
}
      
      





, .







, . , enum



:







fn next(&mut self) -> Option<u32> {
    use Fibs::*;
    match *self {
        Done => None,
        OneLeft(x) => {
            *self = Done;
            Some(x)
        }
        Running(orig_x, orig_y) => {
            *self = match orig_x.checked_add(orig_y) {
                // overflow
                None => OneLeft(orig_y),
                Some(new_y) => Running(orig_y, new_y),
            };

            Some(orig_x)
        }
    }
}
      
      





:







enum FibonacciIterState {
    FirstItem,
    SecondItem,
    NthItem(u64, u64),
    Overflowed,
}

struct FibonacciIterator {
    state: FibonacciIterState,
}

impl FibonacciIterator {
    fn new() -> FibonacciIterator {
        FibonacciIterator{ state: FibonacciIterState::FirstItem }
    }
}

impl Iterator for FibonacciIterator {
    type Item = u64;
    fn next(&mut self) -> Option<<FibonacciIterator as Iterator>::Item> {
        match self.state {
            FibonacciIterState::FirstItem => {
                self.state = FibonacciIterState::SecondItem;
                Some(0)
            },
            FibonacciIterState::SecondItem => {
                self.state = FibonacciIterState::NthItem(0, 1);
                Some(1)
            },
            FibonacciIterState::NthItem(prev, last) => {
                if let Some(next) = prev.checked_add(last) {
                    self.state = FibonacciIterState::NthItem(last, next);
                    Some(next)
                } else {
                    self.state = FibonacciIterState::Overflowed;
                    None
                }
            },
            FibonacciIterState::Overflowed => {
                None
            }
        }
    }
}
      
      







, . (Doubler), , . , , , :







struct Doubler<I> {
    iter: I,
}
      
      





main



, , :







fn main() {
    let orig_iter = 1..11; //   1  10
    let doubled_iter = Doubler {
        iter: orig_iter,
    };
    for i in doubled_iter {
        println!("{}", i);
    }
}
      
      





, - Iterator



. :







impl Iterator for Doubler {
}
      
      





:







error[E0107]: wrong number of type arguments: expected 1, found 0
 --> src/main.rs:6:19
  |
6 | impl Iterator for Doubler {
  |                   ^^^^^^^ expected 1 type argument
      
      





, . Doubler



, . :







impl Iterator for Doubler<I> {
}
      
      





. , . (: , ).







:







error[E0412]: cannot find type `I` in this scope
 --> foo.rs:5:27
  |
5 | impl Iterator for Doubler<I> {
  |                           ^ not found in this scope

      
      





? , , . :







impl<I> Iterator for Doubler<I> {
}
      
      





( ), , .







, type Item



next



. u32



:







type Item = u32;
fn next(&mut self) -> Option<u32> {
    unimplemented!()
}
      
      





, unimplemented!



. , !

, . ( : , map



Option



, ):







fn next(&mut self) -> Option<u32> {
    match self.iter.next() {
        None => None,
        Some(x) => Some(x * 2),
    }
}
      
      





, :







error[E0599]: no method named `next` found for type parameter `I` in the current scope
 --> src/main.rs:9:25
  |
9 |         match self.iter.next() {
  |                         ^^^^ method not found in `I`
  |
  = help: items from traits can only be used if the type parameter is bounded by the trait
help: the following traits define an item `next`, perhaps you need to restrict type parameter `I` with one of them:
  |
6 | impl<I: std::iter::Iterator> Iterator for Doubler<I> {
  |      ^^^^^^^^^^^^^^^^^^^^^^
6 | impl<I: std::str::pattern::Searcher> Iterator for Doubler<I> {
  |      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
      
      





, next



Iterator



. . , . , ! , I



Iterator



.







impl<I: Iterator> Iterator for Doubler<I>
      
      





, : I



Iterator



. , , :







error[E0369]: cannot multiply `{integer}` to `<I as std::iter::Iterator>::Item`
  --> src/main.rs:11:31
   |
11 |             Some(x) => Some(x * 2),
   |                             - ^ - {integer}
   |                             |
   |                             <I as std::iter::Iterator>::Item
   |
   = note: the trait `std::ops::Mul` is not implemented for `<I as std::iter::Iterator>::Item`
      
      





. I



— - Iterator



, . , x



, x * 2



I



Item



. , , , !







, u32



, , Item



u32



? !







impl<I: Iterator<Item=u32>> Iterator for Doubler<I>
      
      





, !







: where





, impl



. where



:







impl<I> Iterator for Doubler<I>
    where I: Iterator<Item=u32>
      
      





. (consistency) , where



. . .







u32



, u32



. , main



:







let orig_iter = 1..11u64;
      
      





:







error[E0271]: type mismatch resolving `<std::ops::Range<u64> as std::iter::Iterator>::Item == u32`
  --> src/main.rs:24:14
   |
24 |     for i in doubled_iter {
   |              ^^^^^^^^^^^^ expected `u64`, found `u32`
   |
   = note: required because of the requirements on the impl of `std::iter::Iterator` for `Doubler<std::ops::Range<u64>>`
      
      





, . ! u32



. :







impl<I> Iterator for Doubler<I>
    where I: iterator
{
    type Item = ???;
    fn next(&mut self) -> Option<Self::Item> {
        match self.iter.next() {
            None => None,
            Some(x) => Some(x * 2),
        }
    }
}
      
      





Option<u32>



Option<Self::Item>



<Item = u32>



I: Iterator



. type Item=



? , , Item



. !







type Item = I::Item;
      
      





! , , I::Item



. , Mul



, . :







where
I: Iterator,
I::Item: std::ops::Mul,
      
      





:







error[E0308]: mismatched types
  --> foo.rs:14:29
   |
14 |             Some(x) => Some(x * From::from(2u8)),
   |                             ^^^^^^^^^^^^^^^^^^^ expected std::iter::Iterator::Item, found std::ops::Mul::Output
   |
   = note: expected type `<I as std::iter::Iterator>::Item`
              found type `<<I as std::iter::Iterator>::Item as std::ops::Mul>::Output`
      
      





, Mul



. . , (Force



), (Mass



) (Acceleration



), Mul



, (Mass



) (Acceleration



), (Force



).







, . , , item



:







impl<I> Iterator for Doubler<I>
    whereI: Iterator,
    I::Item: std::ops::Mul<Output=I::Item>,
      
      





:







error[E0308]: mismatched types
  --> foo.rs:14:33
   |
14 |             Some(x) => Some(x * 2),
   |                                 ^ expected associated type, found integral variable
   |
   = note: expected type `<I as std::iter::Iterator>::Item`
              found type `{integer}`
      
      





. 2



, - . , Item



- . , , ( — , ). , , (upcast) u8



From



, ( ).







impl<I> Iterator for Doubler<I>
    where
    I: iterator,
    I::Item: std::ops::Mul<Output=I::Item> + From<u8>,
{
    type Item = I::Item;

    fn next(&mut self) -> Option<Self::Item> {
        match self.iter.next() {
            None => None,
            Some(x) => Some(x * From::from(2u8)),
        }
    }
}
      
      





, - !









x + x



x * 2



. . : , , .







impl<I> Iterator for Doubler<I>
    where
    I: Iterator,
    I::Item: std::ops::Add<Output=I::Item> + Copy,
{
    type Item = I::Item;
    fn next(&mut self) -> Option<Self::Item> {
        match self.iter.next() {
            None => None,
            Some(x) => Some(x + x),
        }
    }
}
      
      







. , , . , . Doubler



, . Empty



, . .







, , . , . , , , .









Doubler



, , . :







fn main() {
    for i in (1..11).map(|x| x * 2) {
        println!("{}", i);
    }
}
      
      





Iterator



, . :







fn main() {
    for i in (1..11).skip(3).map(|x| x + 1).filter(|x| x % 2 == 0) {
        println!("{}", i);
    }
}
      
      





C/C++, :







  • : ,




:







fn main() {
    let my_vec: Vec<u32> = (1..11).collect();
    println!("{:?}", my_vec);
}
      
      





, collect



.









fold



1 10. : sum



.







fold



: . :







fn main() {
    let res = (1..11).fold(0, |x, y| x + y);
    println!("{}", res);
}
      
      





. , Mul



*



? Add



:







fn main() {
    let res = (1..11).fold(0, std::ops::Add::add);
    println!("{}", res);
}
      
      





: , . , From



u8



:







fn sum<I>(iter: I) -> I::Item
    where
    I: Iterator,
    I::Item: std::ops::Add<Output=I::Item> + From<u8>,
{
    iter.fold(From::from(0u8), std::ops::Add::add)
}
      
      






All Articles