简体   繁体   中英

Implementing a custom Iterator Trait

Source code

pub struct Iterating_ex {
    start: u32,
    end: u32,
}

impl Iterator for Iterating_ex {
    type Item = u32;

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

fn main() {
    let example = Iterating_ex {
        start: 0,
        end: 5,
    };
    for i in example {
        println!("{i}");
    }
}

Output

0
1
2
3
4

Individually I understand what each piece of code is trying to do, however I am having trouble understanding the following, possibly due to my lack of understanding of the generic iterator trait;

  1. Does implementing the Iterator trait for a struct automatically generate an iterable data type? In this case, I don't know why a for loop can be used on example .
  2. It seems like the next method is called as a loop until None is returned. How does the code know to do so?

Ad 1 . To be "iterable" in rust means to implement the Iterator trait. Some things however can be turned into an iterator and that is described by another trait IntoIterator . Standard library provides a blanket implementation:

impl<I: Iterator> IntoIterator for I { /* ... */}

Which means that any type that implements Iterator can be turned into one (it's noop). for loops are designed to work with types that implement IntoIterator . That's why you can write for example:

let mut v = vec![1, 2, 3, 4, 5];

for _ in &v {}
for _ in &mut v {}
for _ in v {}

Since types &Vec<T> , &mut Vec<T> and Vec<T> all implement IntoIterator trait. They all are turned into different iterator types of course, and are returning respectively &T , &mut T and T .

Ad 2 . As stated before for loops can be used on types that implement IntoIterator . The documentation explains in detail how it works, but in a nutshell for loop is just a syntax sugar that turns this code:

for x in xs {
    todo!()
}

Into something like this:

let mut xs_iter = xs.into_iter();
while let Some(x) = xs_iter.next() {
    todo!()
}

while loops are also syntax sugar and are de-sugared into loop with a break statement but that's not relevant here.

Side note . I guess that this is just a learning example, and it's great, but the exact same iterator already exists in the standard library as std::ops::Range , so use that it your actual code if you need it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM