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

289: Extending Collections with extend()

Difficulty: 2 Level: Intermediate Append elements from any iterator into an existing collection in place โ€” the in-place alternative to `chain().collect()`.

The Problem This Solves

You have an existing collection and you want to add more elements to it. The naive approach: `let new_vec = existing.into_iter().chain(more).collect()` โ€” but that consumes the original, creates a new allocation, and loses the variable binding. If you're appending in a loop (building up a result incrementally), each iteration creates and destroys a vec. `extend()` adds elements to an existing collection in place, reusing its allocation when possible. It's more efficient than `chain + collect` when you already have a collection and just want to grow it. It also works on any collection that implements `Extend<T>` โ€” `Vec`, `String`, `HashMap`, `HashSet`, `BTreeSet`, and more. OCaml's lists are immutable, so there's no in-place equivalent โ€” you prepend with `::` or use `Buffer.add_string` for strings. Rust's `extend()` is the imperative counterpart to functional `append`.

The Intuition

`collection.extend(iterator)` drains the iterator and pushes each element into the collection โ€” equivalent to calling `push`/`insert` in a loop, but expressed as a single declarative call.
let mut v = vec![1, 2, 3];
v.extend([4, 5, 6]);
// v is now [1, 2, 3, 4, 5, 6]

How It Works in Rust

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

// Extend a Vec
let mut base = vec![1i32, 2, 3];
base.extend([4, 5, 6]);               // from array
base.extend(7..=9);                   // from range
// โ†’ [1, 2, 3, 4, 5, 6, 7, 8, 9]

// Extend String with chars (String implements Extend<char>)
let mut s = String::from("Hello");
s.extend(", world!".chars());
// โ†’ "Hello, world!"

// Extend HashMap โ€” duplicate keys overwrite
let mut map: HashMap<&str, i32> = HashMap::new();
map.insert("a", 1);
map.extend([("b", 2), ("c", 3)]);
// โ†’ {"a": 1, "b": 2, "c": 3}

// Extend HashSet โ€” duplicates are silently ignored
let mut set: HashSet<i32> = [1, 2, 3].iter().copied().collect();
set.extend([3, 4, 5]);  // 3 already present โ€” no duplicate
// โ†’ {1, 2, 3, 4, 5}

// Extend with a transformed iterator
let mut evens = vec![2i32, 4];
evens.extend((1..20).filter(|x| x % 2 == 0).take(3));
// appends [2, 4, 6] to existing [2, 4]
// โ†’ [2, 4, 2, 4, 6]

// Incremental building โ€” more efficient than repeated chain+collect
let mut result: Vec<i32> = Vec::new();
for batch in [[1, 2], [3, 4], [5, 6]] {
 result.extend(batch);  // reuses allocation when possible
}
`extend()` calls `reserve()` internally when it can determine the size hint, pre-allocating space to avoid repeated reallocation.

What This Unlocks

Key Differences

ConceptOCamlRust
Append to collection`lst @ more` (new list)`vec.extend(iter)` (in-place)
String append`Buffer.add_string``string.extend(chars)` or `string.push_str`
HashMap insert many`List.fold_left` + `Hashtbl.add``map.extend(pairs)`
AllocationAlways new allocationReuses existing allocation (amortized)
vs. `chain + collect`Equivalent output`extend` avoids creating a new collection
//! 289. Extending collections with extend()
//!
//! `extend()` appends elements from an iterator to an existing collection in place.

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

fn main() {
    // Extend a Vec
    let mut base = vec![1i32, 2, 3];
    base.extend([4, 5, 6]);
    println!("Extended Vec: {:?}", base);

    // Extend with multiple iterators
    let mut nums = vec![1i32, 2];
    nums.extend(3..=5);
    nums.extend([6, 7, 8]);
    println!("Multi-extend: {:?}", nums);

    // Extend String with chars
    let mut s = String::from("Hello");
    s.extend(", world!".chars());
    println!("Extended String: {}", s);

    // Extend HashMap
    let mut map: HashMap<&str, i32> = HashMap::new();
    map.insert("a", 1);
    map.extend([("b", 2), ("c", 3)]);
    println!("Extended HashMap: {:?}", map);

    // Extend HashSet
    let mut set: HashSet<i32> = [1, 2, 3].iter().copied().collect();
    set.extend([3, 4, 5]); // 3 is duplicate, ignored
    let mut sorted: Vec<i32> = set.into_iter().collect();
    sorted.sort();
    println!("Extended HashSet: {:?}", sorted);

    // Extend with filter
    let mut evens = vec![2i32, 4];
    evens.extend((1..20).filter(|x| x % 2 == 0).take(3));
    println!("Evens extended: {:?}", evens);
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_extend_vec_basic() {
        let mut v = vec![1i32, 2, 3];
        v.extend([4, 5, 6]);
        assert_eq!(v, vec![1, 2, 3, 4, 5, 6]);
    }

    #[test]
    fn test_extend_string() {
        let mut s = String::from("hello");
        s.extend(" world".chars());
        assert_eq!(s, "hello world");
    }

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

    #[test]
    fn test_extend_hashset_dedup() {
        use std::collections::HashSet;
        let mut s: HashSet<i32> = [1, 2].iter().copied().collect();
        s.extend([2, 3]);
        assert_eq!(s.len(), 3);
    }
}
(* 289. Extending collections with extend() - OCaml *)
(* OCaml: List.append or @ to extend lists *)

let () =
  let base = [1; 2; 3] in
  let extension = [4; 5; 6] in
  let combined = base @ extension in
  Printf.printf "Extended: %s\n"
    (String.concat ", " (List.map string_of_int combined));

  (* Extend with multiple sources *)
  let all = base @ [4; 5] @ [6; 7; 8] in
  Printf.printf "Multi-extend: %s\n"
    (String.concat ", " (List.map string_of_int all));

  (* Buffer extension pattern *)
  let buf = Buffer.create 16 in
  Buffer.add_string buf "hello";
  Buffer.add_string buf " ";
  Buffer.add_string buf "world";
  Printf.printf "Buffer: %s\n" (Buffer.contents buf)