๐Ÿฆ€ 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

288: Iterator collect()

Difficulty: 2 Level: Intermediate Materialize a lazy iterator into any collection type โ€” `Vec`, `HashMap`, `HashSet`, `String`, `BTreeMap`, and more โ€” including collecting `Result<Vec<T>>` from a fallible stream.

The Problem This Solves

An iterator is lazy โ€” it produces elements on demand but doesn't store them. At some point you need the results in a concrete data structure you can index, share, or pass to APIs that don't accept iterators. Without `collect()`, you'd write a `for` loop pushing elements into a pre-allocated collection โ€” boilerplate that drowns out the intent. `collect()` generalizes this: any type implementing `FromIterator<T>` can receive the elements. The type you collect into determines how elements are assembled. Collect `(K, V)` pairs into a `HashMap`. Collect `char`s into a `String`. Collect `Option<T>` or `Result<T, E>` โ€” the entire collection short-circuits on the first `None` or `Err`, returning a single `Option<Vec<T>>` or `Result<Vec<T>, E>`. The main challenge is type inference: `collect()` can't infer the target type from the iterator alone. You need either a type annotation on the binding (`let v: Vec<i32> = ...`) or the turbofish (`.collect::<Vec<i32>>()`).

The Intuition

Tell Rust what collection type you want; `collect()` drives the `FromIterator` machinery to assemble all elements into it.

How It Works in Rust

// Vec โ€” the default
let squares: Vec<u32> = (0..5).map(|x| x * x).collect();
// โ†’ [0, 1, 4, 9, 16]

// HashSet โ€” automatic deduplication
let set: HashSet<i32> = vec![1, 2, 2, 3, 3, 3].into_iter().collect();
// set.len() == 3

// HashMap โ€” from (K, V) iterator
let map: HashMap<&str, u32> = [("a", 1), ("b", 2)].into_iter().collect();

// String โ€” from chars
let s: String = ['R', 'u', 's', 't'].iter().collect();
// โ†’ "Rust"

// BTreeMap โ€” sorted by key
let bmap: BTreeMap<i32, i32> = (0..5).map(|x| (x, x*x)).collect();

// Result<Vec<T>> โ€” fail fast on first parse error
let nums: Result<Vec<i32>, _> = ["1", "2", "3"].iter()
 .map(|s| s.parse::<i32>())
 .collect();  // Ok([1, 2, 3])

let broken: Result<Vec<i32>, _> = ["1", "oops", "3"].iter()
 .map(|s| s.parse::<i32>())
 .collect();  // Err(ParseIntError) โ€” stops at first failure
The turbofish syntax: `.collect::<Vec<_>>()` โ€” `_` lets Rust infer the element type, you only specify the container.

What This Unlocks

Key Differences

ConceptOCamlRust
To listNatural โ€” lists are the base type`.collect::<Vec<_>>()`
To set`List.sort_uniq compare` (manual)`.collect::<HashSet<_>>()`
To map`List.fold_left` into Map`.collect::<HashMap<K,V>>()`
Type selectionInferred from contextAnnotation or turbofish required
Fallible collectManual fold with error check`.collect::<Result<Vec<_>, _>>()`
//! 288. Collecting into various collections
//!
//! `collect()` materializes a lazy iterator into any `FromIterator<T>` type.

use std::collections::{HashMap, HashSet, BTreeMap, LinkedList};

fn main() {
    // Collect into Vec
    let squares: Vec<u32> = (0..5).map(|x| x * x).collect();
    println!("Vec: {:?}", squares);

    // Collect into HashSet (deduplicates)
    let words = vec!["apple", "banana", "apple", "cherry", "banana"];
    let set: HashSet<&&str> = words.iter().collect();
    println!("HashSet size: {}", set.len()); // 3 unique

    // Collect into HashMap from iterator of (K, V)
    let keys = ["a", "b", "c"];
    let values = [1u32, 2, 3];
    let map: HashMap<&&str, &u32> = keys.iter().zip(values.iter()).collect();
    println!("HashMap: {:?}", map);

    // Collect into String from chars
    let chars = ['R', 'u', 's', 't'];
    let s: String = chars.iter().collect();
    println!("String from chars: {}", s);

    // Collect into String from words with separator
    let ws = vec!["hello", "world", "rust"];
    let joined: String = ws.join(" ");
    println!("Joined: {}", joined);

    // Collect into BTreeMap (sorted keys)
    let bmap: BTreeMap<i32, i32> = (0..5).map(|x| (x, x * x)).collect();
    println!("BTreeMap: {:?}", bmap);

    // Collect Result<Vec<T>> from Iterator<Result<T>>
    let strs = ["1", "2", "3"];
    let nums: Result<Vec<i32>, _> = strs.iter().map(|s| s.parse::<i32>()).collect();
    println!("Result<Vec>: {:?}", nums);

    // Collect into LinkedList
    let ll: LinkedList<i32> = (1..=4).collect();
    println!("LinkedList: {:?}", ll);
}

#[cfg(test)]
mod tests {
    use std::collections::{HashMap, HashSet};

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

    #[test]
    fn test_collect_hashset_dedup() {
        let set: HashSet<i32> = vec![1, 2, 2, 3, 3, 3].into_iter().collect();
        assert_eq!(set.len(), 3);
    }

    #[test]
    fn test_collect_hashmap() {
        let map: HashMap<i32, i32> = (0..3).map(|x| (x, x*x)).collect();
        assert_eq!(map[&2], 4);
    }

    #[test]
    fn test_collect_string() {
        let s: String = ['a', 'b', 'c'].iter().collect();
        assert_eq!(s, "abc");
    }

    #[test]
    fn test_collect_result_vec() {
        let ok: Result<Vec<i32>, _> = ["1", "2", "3"].iter()
            .map(|s| s.parse::<i32>()).collect();
        assert_eq!(ok.unwrap(), vec![1, 2, 3]);
        let err: Result<Vec<i32>, _> = ["1", "x", "3"].iter()
            .map(|s| s.parse::<i32>()).collect();
        assert!(err.is_err());
    }
}
(* 288. Collecting into various collections - OCaml *)

module StringSet = Set.Make(String)
module StringMap = Map.Make(String)

let () =
  (* List (default collection) *)
  let nums = List.init 5 (fun i -> i * i) in
  Printf.printf "List: %s\n"
    (String.concat ", " (List.map string_of_int nums));

  (* Set (unique elements) *)
  let words = ["apple"; "banana"; "apple"; "cherry"; "banana"] in
  let set = List.fold_left (fun s w -> StringSet.add w s) StringSet.empty words in
  Printf.printf "Set: %s\n" (String.concat ", " (StringSet.elements set));

  (* Map from key-value pairs *)
  let pairs = [("a", 1); ("b", 2); ("c", 3)] in
  let map = List.fold_left (fun m (k, v) -> StringMap.add k v m) StringMap.empty pairs in
  Printf.printf "Map a=%d, b=%d\n" (StringMap.find "a" map) (StringMap.find "b" map);

  (* String from chars *)
  let chars = ['h'; 'e'; 'l'; 'l'; 'o'] in
  let s = String.concat "" (List.map (String.make 1) chars) in
  Printf.printf "String: %s\n" s