Range Over Iterators in Rust

Our first program will demonstrate iterating over various elements using iterators. Here’s how to do it in the target language.

use std::cell::RefCell;
use std::rc::Rc;

struct List<T> {
    head: Option<Rc<RefCell<Element<T>>>>,
    tail: Option<Rc<RefCell<Element<T>>>>,
}

struct Element<T> {
    next: Option<Rc<RefCell<Element<T>>>>,
    val: T,
}

impl<T> List<T> {
    fn new() -> Self {
        List { head: None, tail: None }
    }

    fn push(&mut self, v: T) {
        let new_tail = Rc::new(RefCell::new(Element { next: None, val: v }));
        match self.tail.take() {
            Some(old_tail) => old_tail.borrow_mut().next = Some(new_tail.clone()),
            None => self.head = Some(new_tail.clone())
        }
        self.tail = Some(new_tail);
    }

    fn all(&self) -> impl Iterator<Item = T>
    where
        T: Clone,
    {
        struct AllIter<T>(Option<Rc<RefCell<Element<T>>>>);
        impl<T> Iterator for AllIter<T>
        where
            T: Clone,
        {
            type Item = T;
            fn next(&mut self) -> Option<T> {
                self.0.take().map(|e| {
                    let el = e.borrow();
                    self.0 = el.next.clone();
                    el.val.clone()
                })
            }
        }
        AllIter(self.head.clone())
    }
}

fn gen_fib() -> impl Iterator<Item = i32> {
    struct FibIter(i32, i32);
    impl Iterator for FibIter {
        type Item = i32;
        fn next(&mut self) -> Option<i32> {
            let (a, b) = (self.0, self.1);
            self.0 = b;
            self.1 = a + b;
            Some(a)
        }
    }
    FibIter(1, 1)
}

fn main() {
    let mut lst = List::new();
    lst.push(10);
    lst.push(13);
    lst.push(23);

    for e in lst.all() {
        println!("{}", e);
    }

    let all: Vec<_> = lst.all().collect();
    println!("all: {:?}", all);

    for n in gen_fib() {
        if n >= 10 {
            break;
        }
        println!("{}", n);
    }
}

In Rust, we define our List and Element structs for a generic type T. We use RefCell and Rc for interior mutability and reference counting, respectively. The push method adds new elements to the list.

The all method returns an iterator over the list elements. This iterator is implemented in the AllIter struct, which uses the Iterator trait to define the iteration behavior.

We also define a gen_fib function that returns an iterator over the Fibonacci sequence, using the Iterator trait to generate new Fibonacci numbers.

In the main function, we create a list, add elements, and demonstrate iterating over list elements and Fibonacci numbers, using Rust’s collection and iteration features.

This example illustrates how to use Rust’s iterators effectively and how to create custom iterators for complex data structures.