Rust crashcourse. Iteradores

Abaixo está uma tradução de uma parte da série de artigos Rust Crash Course de Michael Snoiman, que se concentra em iteradores. O material me pareceu um sucesso em termos de acessibilidade, então decidi publicar a tradução que fiz para mim. Espero que isso seja útil para alguém. Se este material for interessante, publicarei mais algumas traduções desta série.







Também tentei traduzir o mais próximo possível do estilo do autor, mas reduzi alguns interdomínios e exclamações que não são muito significativos para o significado.







Mais iteradores!



Para mim, descobri que a maneira mais fácil de entender como funcionam os iteradores é escrever alguns deles eu mesmo, então é por aí que começamos.







Vamos fazer programação guiada por compilador. Discutimos anteriormente que existe uma característica Iterator



. Portanto, aposto que precisamos criar um novo tipo de dados e fornecer uma implementação para esse traço. Vamos começar com algo simples, um iterador que não produz nenhum valor.







struct Empty;

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





Panic ( panic!()



) é uma forma de encerrar a thread atual quando ocorre uma situação impossível. Isso é semelhante às exceções de tempo de execução em outras linguagens, exceto que não pode ser recuperado. Portanto, ele só deve ser usado para tais situações.







Vamos compilar isso e obter uma mensagem de erro ú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`
      
      





Vamos adicionar uma implementação vazia:







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);
    }
}
      
      







, .







Vamos começar com a solução mais simples







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);
    }
}
      
      





No entanto, se você substituir take(10)



por take(47)



, a saída do programa ficará assim:







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





Uma solução pode ser usar um tipo u64



, mas isso apenas adia o problema. Em vez disso, podemos usar a adição de estouro:







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