Reputation: 383
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;
example
.next
method is called as a loop until None
is returned. How does the code know to do so?Upvotes: 2
Views: 879
Reputation: 6255
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.
Upvotes: 6