๐Ÿฆ€ Functional Rust
๐ŸŽฌ How Rust Iterators Work Lazy evaluation, chaining, collect(), and zero-cost abstractions.
๐Ÿ“ Text version (for readers / accessibility)

โ€ข Iterators are lazy โ€” .map(), .filter(), .take() build a chain but do no work until consumed

โ€ข .collect() triggers evaluation, transforming the chain into a Vec, HashMap, or other collection

โ€ข Zero-cost abstraction: iterator chains compile to the same machine code as hand-written loops

โ€ข .iter() borrows, .into_iter() consumes, .iter_mut() borrows mutably

โ€ข Chaining replaces nested loops with a readable, composable pipeline

085: Iterator Trait

Difficulty: 2 Level: Intermediate Implement the `Iterator` trait for a custom type โ€” define just `next()` and get `map`, `filter`, `take`, `sum`, `collect`, and 70+ other methods for free.

The Problem This Solves

You have a custom data structure and you want to loop over it, transform it, filter it, sum it. Without implementing `Iterator`, you're stuck writing your own `for_each`, `map`, `filter` methods by hand โ€” or forcing callers to extract a `Vec` first. Rust's `Iterator` trait is a single-method protocol: implement `fn next(&mut self) -> Option<Self::Item>` and you get the entire iterator toolkit at no extra cost. Every adapter (`map`, `filter`, `enumerate`, `chain`) and every consumer (`sum`, `collect`, `find`, `max`) in the standard library works with your type automatically. This is one of the clearest examples of Rust's trait system paying off: one small implementation unlocks an enormous amount of functionality.

The Intuition

In Python, you implement `__iter__` and `__next__` on a class โ€” and then `for`, `list()`, `sum()`, and all list comprehensions work with your type. In Java, you implement `Iterator<T>` with `hasNext()` and `next()`. In OCaml, you implement a `Seq`-compatible generator. Rust's model is closer to Python's: one method (`next`), infinite power. The difference is that all the adapter methods are defined directly on the trait, so `my_iter.map(f).filter(p).take(5)` chains with zero overhead โ€” each adapter is a zero-cost wrapper that forwards `next()` calls. The associated type `Item` tells the compiler what type this iterator yields. The iterator itself decides โ€” callers don't need to specify it.

How It Works in Rust

// A finite iterator over a range
struct Range { current: i32, end: i32 }

impl Iterator for Range {
 type Item = i32;      // this iterator yields i32s

 fn next(&mut self) -> Option<i32> {
     if self.current >= self.end {
         None           // signals end of iteration
     } else {
         let val = self.current;
         self.current += 1;
         Some(val)      // yield current value, advance state
     }
 }
}

// You get all of this for FREE from one next() implementation:
let nums: Vec<i32> = Range { current: 1, end: 6 }.collect();       // [1,2,3,4,5]
let doubled: Vec<i32> = Range { current: 1, end: 6 }.map(|x| x * 2).collect();
let sum: i32 = Range { current: 1, end: 101 }.sum();               // 5050
// An infinite iterator โ€” returns Some forever
struct Counter { current: u64 }

impl Iterator for Counter {
 type Item = u64;
 fn next(&mut self) -> Option<u64> {
     let val = self.current;
     self.current += 1;
     Some(val)   // never returns None โ€” use .take(n) to stop
 }
}

// Safe to chain because nothing is computed until consumed
let odd_squares: Vec<u64> = Counter { current: 1 }
 .map(|x| x * x)
 .filter(|x| x % 2 == 1)
 .take(5)
 .collect();   // [1, 9, 25, 49, 81]
// Generic functions work with any iterator via Iterator bound
fn sum_first_n<I: Iterator<Item = i32>>(iter: I, n: usize) -> i32 {
 iter.take(n).sum()
}

What This Unlocks

Key Differences

ConceptOCamlRust
Iterator protocol`Seq.t = unit -> node` (functional, lazy)`Iterator` trait with `next(&mut self)` (stateful)
Item typeInferred or in module signature`type Item` (associated type)
Infinite sequences`Seq.unfold``impl Iterator` that always returns `Some(...)`
Free combinators`Seq.map`, `Seq.filter` from stdlib70+ methods auto-available from the trait
TerminationReturns `Seq.Nil`Returns `None` from `next()`
// Example 085: Iterator Trait
// OCaml Seq โ†’ Rust Iterator

// === Approach 1: Implementing Iterator for a custom type ===
struct Range {
    current: i32,
    end_: i32,
}

impl Range {
    fn new(start: i32, end_: i32) -> Self {
        Range { current: start, end_ }
    }
}

impl Iterator for Range {
    type Item = i32;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current >= self.end_ {
            None
        } else {
            let val = self.current;
            self.current += 1;
            Some(val)
        }
    }
}

// === Approach 2: Iterator with map/filter (free from trait) ===
struct Counter {
    current: u64,
}

impl Counter {
    fn from(start: u64) -> Self {
        Counter { current: start }
    }
}

impl Iterator for Counter {
    type Item = u64;

    fn next(&mut self) -> Option<Self::Item> {
        let val = self.current;
        self.current += 1;
        Some(val) // infinite!
    }
}

// === Approach 3: Iterator via IntoIterator ===
struct Repeat<T: Clone> {
    value: T,
    remaining: usize,
}

impl<T: Clone> Repeat<T> {
    fn new(value: T, count: usize) -> Self {
        Repeat { value, remaining: count }
    }
}

impl<T: Clone> Iterator for Repeat<T> {
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        if self.remaining == 0 {
            None
        } else {
            self.remaining -= 1;
            Some(self.value.clone())
        }
    }
}

// Generic function working with any iterator
fn sum_first_n<I: Iterator<Item = i32>>(iter: I, n: usize) -> i32 {
    iter.take(n).sum()
}

fn collect_mapped<I, F, B>(iter: I, f: F) -> Vec<B>
where
    I: Iterator,
    F: Fn(I::Item) -> B,
{
    iter.map(f).collect()
}

fn main() {
    // Custom Range iterator
    let range = Range::new(1, 6);
    let nums: Vec<i32> = range.collect();
    println!("Range: {:?}", nums);

    // Map and filter come free
    let doubled: Vec<i32> = Range::new(1, 6).map(|x| x * 2).collect();
    println!("Doubled: {:?}", doubled);

    let evens: Vec<i32> = Range::new(1, 11).filter(|x| x % 2 == 0).collect();
    println!("Evens: {:?}", evens);

    // Infinite counter with take
    let first5: Vec<u64> = Counter::from(0).take(5).collect();
    println!("First 5: {:?}", first5);

    // Chained
    let result: Vec<u64> = Counter::from(1)
        .map(|x| x * x)
        .filter(|x| x % 2 == 1)
        .take(5)
        .collect();
    println!("Odd squares: {:?}", result);

    // Repeat
    let hellos: Vec<&str> = Repeat::new("hello", 3).collect();
    println!("Repeats: {:?}", hellos);
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_range() {
        let v: Vec<i32> = Range::new(1, 6).collect();
        assert_eq!(v, vec![1, 2, 3, 4, 5]);
    }

    #[test]
    fn test_empty_range() {
        let v: Vec<i32> = Range::new(5, 5).collect();
        assert!(v.is_empty());
    }

    #[test]
    fn test_range_map() {
        let v: Vec<i32> = Range::new(1, 4).map(|x| x * 10).collect();
        assert_eq!(v, vec![10, 20, 30]);
    }

    #[test]
    fn test_range_filter() {
        let v: Vec<i32> = Range::new(1, 11).filter(|x| x % 3 == 0).collect();
        assert_eq!(v, vec![3, 6, 9]);
    }

    #[test]
    fn test_counter_take() {
        let v: Vec<u64> = Counter::from(10).take(3).collect();
        assert_eq!(v, vec![10, 11, 12]);
    }

    #[test]
    fn test_counter_chain() {
        let sum: u64 = Counter::from(1).take(100).sum();
        assert_eq!(sum, 5050);
    }

    #[test]
    fn test_repeat() {
        let v: Vec<i32> = Repeat::new(42, 4).collect();
        assert_eq!(v, vec![42, 42, 42, 42]);
    }

    #[test]
    fn test_sum_first_n() {
        let sum = sum_first_n(Range::new(1, 100), 10);
        assert_eq!(sum, 55);
    }

    #[test]
    fn test_collect_mapped() {
        let v = collect_mapped(Range::new(1, 4), |x| x.to_string());
        assert_eq!(v, vec!["1", "2", "3"]);
    }
}
(* Example 085: Iterator Trait *)
(* OCaml Seq โ†’ Rust Iterator *)

(* Approach 1: Using Seq (lazy sequences) *)
let range start stop =
  let rec aux n () =
    if n >= stop then Seq.Nil
    else Seq.Cons (n, aux (n + 1))
  in
  aux start

let seq_to_list seq =
  Seq.fold_left (fun acc x -> x :: acc) [] seq |> List.rev

(* Approach 2: Custom iterator via closure *)
type 'a iterator = {
  next : unit -> 'a option;
}

let range_iter start stop =
  let current = ref start in
  { next = fun () ->
    if !current >= stop then None
    else begin
      let v = !current in
      incr current;
      Some v
    end
  }

let iter_to_list it =
  let rec aux acc =
    match it.next () with
    | None -> List.rev acc
    | Some v -> aux (v :: acc)
  in
  aux []

let iter_map f it =
  { next = fun () ->
    match it.next () with
    | None -> None
    | Some v -> Some (f v)
  }

let iter_filter pred it =
  let rec find () =
    match it.next () with
    | None -> None
    | Some v -> if pred v then Some v else find ()
  in
  { next = find }

(* Approach 3: Using List as iterator source *)
let counter_from n =
  let c = ref n in
  { next = fun () ->
    let v = !c in
    c := v + 1;
    Some v
  }

let take n it =
  let count = ref 0 in
  { next = fun () ->
    if !count >= n then None
    else begin
      incr count;
      it.next ()
    end
  }

(* Tests *)
let () =
  let s = range 1 6 in
  assert (seq_to_list s = [1; 2; 3; 4; 5]);

  let it = range_iter 1 6 in
  assert (iter_to_list it = [1; 2; 3; 4; 5]);

  let it2 = range_iter 1 11 in
  let doubled = iter_map (fun x -> x * 2) it2 in
  let evens = iter_filter (fun x -> x <= 10) doubled in
  assert (iter_to_list evens = [2; 4; 6; 8; 10]);

  let inf = counter_from 0 in
  let first5 = take 5 inf in
  assert (iter_to_list first5 = [0; 1; 2; 3; 4]);

  Printf.printf "โœ“ All tests passed\n"

๐Ÿ“Š Detailed Comparison

Comparison: Iterator Trait

Core Implementation

OCaml โ€” Seq:

๐Ÿช Show OCaml equivalent
let range start stop =
let rec aux n () =
 if n >= stop then Seq.Nil
 else Seq.Cons (n, aux (n + 1))
in
aux start

Rust โ€” Iterator trait:

struct Range { current: i32, end_: i32 }

impl Iterator for Range {
 type Item = i32;
 fn next(&mut self) -> Option<i32> {
     if self.current >= self.end_ { None }
     else { let v = self.current; self.current += 1; Some(v) }
 }
}

Map/Filter (Manual vs Free)

OCaml โ€” Must implement manually for custom iterators:

๐Ÿช Show OCaml equivalent
let iter_map f it =
{ next = fun () -> match it.next () with
 | None -> None | Some v -> Some (f v) }

Rust โ€” Free from Iterator trait:

// Just implementing next() gives you:
Range::new(1, 6).map(|x| x * 2).filter(|x| x > 5).collect::<Vec<_>>()

Infinite Sequences

OCaml:

๐Ÿช Show OCaml equivalent
let counter_from n =
let c = ref n in
{ next = fun () -> let v = !c in c := v + 1; Some v }

let first5 = take 5 (counter_from 0)

Rust:

impl Iterator for Counter {
 type Item = u64;
 fn next(&mut self) -> Option<u64> {
     let v = self.current; self.current += 1; Some(v)
 }
}

let first5: Vec<u64> = Counter::from(0).take(5).collect();