rust-unofficial / patterns

A catalogue of Rust design patterns, anti-patterns and idioms
https://rust-unofficial.github.io/patterns/
Mozilla Public License 2.0
7.85k stars 354 forks source link

Iterator #229

Open simonsan opened 3 years ago

simonsan commented 3 years ago

Tracking issue for merging: https://github.com/lpxxn/rust-design-pattern/blob/master/behavioral/iterator.rs

Example:

//! Iterator is a behavioral design pattern that lets you traverse elements of a collection without exposing its underlying representation (list, stack, tree, etc.).

trait Iterator<T> {
    fn next(&mut self) -> Option<T>;
    fn current(&self) -> Option<T>;
    fn has_next(&self) -> bool;
    fn reset(&mut self);
}

struct Container<T> {
    data: Vec<T>,
}

struct ConcreteIterator<'a, T> {
    idx: usize,
    container: &'a Container<T>,
}

impl<'a, T: Clone> ConcreteIterator<'a, T> {
    fn new(container: &'a Container<T>) -> ConcreteIterator<T> {
        ConcreteIterator { idx: 0, container }
    }
}

impl<'a, T: Clone> Iterator<T> for ConcreteIterator<'a, T> {
    fn next(&mut self) -> Option<T> {
        let item = self.container.data.get(self.idx).cloned();
        self.idx += 1;
        item
    }
    fn current(&self) -> Option<T> {
        self.container.data.get(self.idx).cloned()
    }
    fn has_next(&self) -> bool {
        self.container.data.len() > self.idx
    }
    fn reset(&mut self) {
        self.idx = 0;
    }
}

impl<T: Clone> Container<T> {
    fn new() -> Container<T> {
        Container { data: Vec::new() }
    }
    fn add_item(&mut self, item: T) {
        self.data.push(item);
    }
    fn iter(&self) -> impl Iterator<T> + '_ {
        ConcreteIterator::new(self)
    }
}

fn main() {
    let mut c = Container::new();
    c.add_item(1);
    c.add_item(2);
    c.add_item(3);

    let mut iter = c.iter();
    let has_next = iter.has_next();
    assert_eq!(has_next, true);
    let item = iter.next();
    println!("item: {:?}", item);
    iter.reset();
    while iter.has_next() {
        let v = iter.next().unwrap();
        println!("item: {}", v);
    }
    let item = iter.next();
    assert_eq!(item, None);
}
simonsan commented 3 years ago

Tracking discussion on merging: https://github.com/lpxxn/rust-design-pattern/issues/7

lpxxn commented 3 years ago

i relicense to MPL-2.0,you can use and change my code.