13.4 Advanced Iterator Concepts

13.4.1 Double-Ended Iterators

Double-Ended Iterators allow traversal from both the front and the back.

Example:

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];
    let mut iter = numbers.iter();
    assert_eq!(iter.next(), Some(&1));
    assert_eq!(iter.next_back(), Some(&5));
    assert_eq!(iter.next(), Some(&2));
    assert_eq!(iter.next_back(), Some(&4));
    assert_eq!(iter.next(), Some(&3));
    assert_eq!(iter.next_back(), None);
}

Implementing DoubleEndedIterator:

impl DoubleEndedIterator for MyRange {
    fn next_back(&mut self) -> Option<Self::Item> {
        if self.current < self.end {
            self.end -= 1;
            Some(self.end)
        } else {
            None
        }
    }
}

13.4.2 Fused Iterators

A Fused Iterator guarantees that after returning None, it will always return None.

Marking an Iterator as Fused:

#![allow(unused)]
fn main() {
use std::iter::FusedIterator;
impl FusedIterator for MyRange {}
}

13.4.3 Iterator Fusion

Iterator Fusion optimizes iterators by stopping computations after completion.

Example:

fn main() {
    let numbers = vec![1, 2, 3];
    let mut iter = numbers.iter().filter(|&&x| x > 1);
    assert_eq!(iter.next(), Some(&2));
    assert_eq!(iter.next(), Some(&3));
    assert_eq!(iter.next(), None);
    assert_eq!(iter.next(), None); // No further computation
}