Rust crashcourse. Iterators

Below is a translation of one part of the Rust Crash Course article series by Michael Snoiman, which focuses on iterators. The material seemed to me to be successful in terms of accessibility, so I decided to publish the translation I made for myself. Hope this is useful to someone. If this material is interesting, then I will publish a few more translations from this series.







I also tried to translate as close to the author's style as possible, but reduced a few interdomes and exclamations that are not very significant for the meaning.







More iterators!



For myself, I've found that the easiest way to understand how iterators work is by writing a few of them myself, so that's where we start.







Let's do compiler-guided programming. We discussed earlier that there is a trait Iterator



. So I bet we need to create a new datatype and provide an implementation for this trait. Let's start with something simple, an iterator that produces no values ​​at all.







struct Empty;

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





Panic ( panic!()



) is a way to terminate the current thread when an impossible situation occurs. This is similar to runtime exceptions in other languages, except that it cannot be recovered. So it should only be used for such situations.







Let's compile this and get a helpful error message:







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`
      
      





Let's add an empty implementation:







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







, .













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