You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The default impls provided by the `Iterator` trait for the methods `size_hint`, `count`, `last`, and `nth` are suboptimal if we know the exact size of the data we're iterating over and have have fast random access into it.
4753
+
4754
+
To illustrate this point let's start by defining a type called `Range` which impls `Iterator` that we can calculate the exact size of:
4755
+
4756
+
```rust
4757
+
structRange {
4758
+
start:usize,
4759
+
end:usize,
4760
+
}
4761
+
4762
+
implIteratorforRange {
4763
+
typeItem=usize;
4764
+
fnnext(&mutself) ->Option<Self::Item> {
4765
+
letcurrent=self.start;
4766
+
self.start +=1;
4767
+
ifcurrent<self.end {
4768
+
Some(current)
4769
+
} else {
4770
+
None
4771
+
}
4772
+
}
4773
+
}
4774
+
```
4775
+
4776
+
Here's the default `size_hint` impl that `Range` would get from the `Iterator` trait:
4777
+
4778
+
```rust
4779
+
fnsize_hint(&self) -> (usize, Option<usize>) {
4780
+
(0, None)
4781
+
}
4782
+
```
4783
+
4784
+
It's not useful at all! The lower bound is hardcoded to `0` and the upper bound is hardcoded to `None`, which is the same as saying _"I have no clue how big this iterator is, it can have anywhere from zero to infinity remaining items in it."_
4785
+
4786
+
Yet we can precisely calculate how many items are remaining in `Range` and provide an actually useful `size_hint` impl:
4787
+
4788
+
```rust
4789
+
implIteratorforRange {
4790
+
// ...
4791
+
fnsize_hint(&self) -> (usize, Option<usize>) {
4792
+
letsize=self.end -self.start;
4793
+
(size, Some(size))
4794
+
}
4795
+
}
4796
+
```
4797
+
4798
+
We can also now impl `ExactSizeIterator` for `Range` because it's a marker trait that marks the type as having an accurate `size_hint` impl:
4799
+
4800
+
```rust
4801
+
implExactSizeIteratorforRange {}
4802
+
```
4803
+
4804
+
We should also provide our own impls for `count`, `last`, and `nth` as their default impls assume the size of the iterator is unknown and rely on repeatedly calling `next`. Here's a simplified version of the default `count` impl as an example:
4805
+
4806
+
```rust
4807
+
fncount(self) ->usize {
4808
+
letmutaccum=0;
4809
+
whileletSome(x) =self.next() {
4810
+
accum+=1;
4811
+
}
4812
+
accum
4813
+
}
4814
+
```
4815
+
4816
+
If we had a `Range` of size one million that's one million times the `next` function would have to be called to `count` it! We can do much better:
0 commit comments