Crashcourse de rouille. Itérateurs

Vous trouverez ci-dessous une traduction d'une partie de la série d'articles Rust Crash Course de Michael Snoiman, qui se concentre sur les itérateurs. Le matériel me semblait être un succès en termes d'accessibilité, j'ai donc décidé de publier la traduction que j'avais faite pour moi-même. J'espère que cela est utile à quelqu'un. Si ce matériel est intéressant, je publierai quelques traductions supplémentaires de cette série.







J'ai également essayé de traduire au plus près du style de l'auteur, mais j'ai réduit quelques interdomaines et exclamations qui ne sont pas très significatifs pour le sens.







Plus d'itérateurs!



Pour ma part, j'ai trouvé que le moyen le plus simple de comprendre le fonctionnement des itérateurs est d'en écrire quelques-uns moi-même, c'est par là que nous commençons.







Faisons de la programmation guidée par le compilateur. Nous avons discuté plus tôt qu'il y a un trait Iterator



. Je parie donc que nous devons créer un nouveau type de données et fournir une implémentation pour ce trait. Commençons par quelque chose de simple, un itérateur qui ne produit aucune valeur.







struct Empty;

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





Panic ( panic!()



) est un moyen de terminer le thread en cours lorsqu'une situation impossible se produit. Ceci est similaire aux exceptions d'exécution dans d'autres langues, sauf qu'il ne peut pas être récupéré. Il ne devrait donc être utilisé que pour de telles situations.







Compilons ceci et obtenons un message d'erreur utile:







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`
      
      





Ajoutons une implémentation vide:







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







, .







Commençons par la solution la plus 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);
    }
}
      
      





Cependant, si vous remplacez take(10)



par take(47)



, la sortie du programme ressemblera à ceci:







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