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

278: Iterator last()

Difficulty: 1 Level: Beginner Consume the entire iterator and return the final element wrapped in `Option<T>`, or `None` if empty.

The Problem This Solves

You want the last element of a sequence โ€” the final log entry, the last matching result, the most recently added item. On a slice you can use `.last()` for an O(1) reference. But on an arbitrary iterator โ€” one produced by `filter`, `map`, or `lines()` โ€” there's no O(1) shortcut. You have to consume the whole thing to find the end. Without `last()`, you'd fold with `None` as the accumulator: `iter.fold(None, |_, x| Some(x))`. That works but hides intent. `last()` is one word that says exactly what you mean. For slices: prefer `slice.last()` directly โ€” it returns `Option<&T>` in O(1). The iterator's `last()` is for pipelines where you don't have a slice reference, like after a chain of adapters.

The Intuition

Advance through the entire iterator, discarding everything except the final element, then return it as `Option<T>`.

How It Works in Rust

let nums = [1i32, 2, 3, 4, 5];

// Iterator's last() โ€” O(n), consumes the iterator
nums.iter().last();  // Some(&5)

// Slice's last() โ€” O(1), returns a reference, doesn't consume
nums.last();  // Some(&5)

// Empty โ†’ None (safe, no panic)
let empty: Vec<i32> = vec![];
empty.iter().last();  // None

// Last after filtering โ€” O(n), traverses the whole range
let last_even = (1..=10).filter(|x| x % 2 == 0).last();  // Some(10)

// Last word in a sentence
"the quick brown fox".split_whitespace().last();  // Some("fox")

// Last non-empty line of a file
let text = "line1\nline2\nline3";
text.lines().last();  // Some("line3")
Key distinction: when you call `last()` on an iterator adapter chain, the entire chain runs to completion. This is fine for small data; think twice before calling `last()` on a million-element filtered stream when you only need the final value.

What This Unlocks

Key Differences

ConceptOCamlRust
Last of list`List.nth lst (List.length lst - 1)``iter.last()`
Empty handling`Invalid_argument` exceptionReturns `None`
O(1) shortcut`Array.(arr.(Array.length arr - 1))``slice.last()` (not iter)
ComplexityO(n) for listsO(n) for iterators, O(1) for slices
After callingList still availableIterator consumed
//! 278. Getting the last element
//!
//! `last()` consumes the iterator to return `Option<T>` with the final element.

fn main() {
    let nums = [1i32, 2, 3, 4, 5];

    // Iterator's last() โ€” consumes entire iterator
    println!("Last: {:?}", nums.iter().last());

    // Slice's last() โ€” O(1), returns reference
    println!("Slice last: {:?}", nums.last());

    // Empty
    let empty: Vec<i32> = vec![];
    println!("Last of empty: {:?}", empty.iter().last());

    // Last element after filtering
    let last_even = (1..=10).filter(|x| x % 2 == 0).last();
    println!("Last even in 1..10: {:?}", last_even);

    // Last word in a sentence
    let sentence = "the quick brown fox";
    let last_word = sentence.split_whitespace().last();
    println!("Last word: {:?}", last_word);

    // Practical: last line of a multiline string
    let text = "line1
line2
line3
line4";
    let last_line = text.lines().last();
    println!("Last line: {:?}", last_line);
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_last_basic() {
        let v = [1i32, 2, 3, 4, 5];
        assert_eq!(v.iter().last(), Some(&5));
    }

    #[test]
    fn test_last_empty() {
        let empty: Vec<i32> = vec![];
        assert_eq!(empty.iter().last(), None);
    }

    #[test]
    fn test_last_after_filter() {
        let last_even = (1i32..=10).filter(|x| x % 2 == 0).last();
        assert_eq!(last_even, Some(10));
    }

    #[test]
    fn test_last_single() {
        assert_eq!([42i32].iter().last(), Some(&42));
    }
}
(* 278. Getting the last element - OCaml *)

let last = function
  | [] -> None
  | lst -> Some (List.nth lst (List.length lst - 1))

let () =
  let nums = [1; 2; 3; 4; 5] in
  Printf.printf "Last: %s\n" (match last nums with Some n -> string_of_int n | None -> "None");
  Printf.printf "Last of []: %s\n" (match last [] with Some _ -> "Some" | None -> "None");

  let words = ["apple"; "banana"; "cherry"] in
  Printf.printf "Last word: %s\n"
    (match last words with Some w -> w | None -> "None");

  (* Last filtered element *)
  let last_even = last (List.filter (fun x -> x mod 2 = 0) nums) in
  Printf.printf "Last even: %s\n"
    (match last_even with Some n -> string_of_int n | None -> "None")