Skip to content

Core Concept: Closures & Iterators ​

Updated Mar 2026

Overview ​

Closures are anonymous functions that capture variables from their environment. Iterators provide a lazy, composable way to process sequences. Together they enable Rust's zero-cost functional programming style.

Closures ​

Basic Syntax ​

rust
fn main() {
    // Full syntax
    let add = |a: i32, b: i32| -> i32 { a + b };

    // Type inference (most common)
    let add = |a, b| a + b;
    let result = add(1, 2);

    // Multi-line
    let process = |x: i32| {
        let doubled = x * 2;
        let formatted = format!("Result: {doubled}");
        formatted
    };
}

Capture Modes ​

rust
fn main() {
    let name = String::from("Alice");

    // Fn — captures by immutable reference
    let greet = || println!("Hello, {name}!");
    greet();
    greet();  // Can call multiple times
    println!("{name}");  // name still valid

    // FnMut — captures by mutable reference
    let mut count = 0;
    let mut increment = || {
        count += 1;
        count
    };
    println!("{}", increment());  // 1
    println!("{}", increment());  // 2

    // FnOnce — captures by value (moves)
    let name = String::from("Bob");
    let consume = move || {
        println!("Consumed: {name}");
        drop(name);  // Takes ownership
    };
    consume();
    // consume();  // ERROR: already called (FnOnce)
    // println!("{name}");  // ERROR: name was moved
}

move Keyword ​

rust
use std::thread;

fn main() {
    let data = vec![1, 2, 3];

    // move forces closure to take ownership of all captured variables
    let handle = thread::spawn(move || {
        println!("{data:?}");  // data is moved into the thread
    });

    // println!("{data:?}");  // ERROR: data was moved
    handle.join().unwrap();
}

Closures as Function Parameters ​

rust
// Accept any closure with matching signature
fn apply<F: Fn(i32) -> i32>(f: F, x: i32) -> i32 {
    f(x)
}

fn apply_mut<F: FnMut(i32)>(mut f: F, items: &[i32]) {
    for &item in items {
        f(item);
    }
}

fn apply_once<F: FnOnce() -> String>(f: F) -> String {
    f()
}

fn main() {
    let doubled = apply(|x| x * 2, 5);  // 10

    let mut sum = 0;
    apply_mut(|x| sum += x, &[1, 2, 3]);
    println!("Sum: {sum}");  // 6

    let name = String::from("world");
    let greeting = apply_once(move || format!("Hello, {name}"));
    println!("{greeting}");
}

Returning Closures ​

rust
fn make_adder(x: i32) -> impl Fn(i32) -> i32 {
    move |y| x + y
}

fn make_counter() -> impl FnMut() -> i32 {
    let mut count = 0;
    move || {
        count += 1;
        count
    }
}

fn main() {
    let add5 = make_adder(5);
    println!("{}", add5(3));  // 8

    let mut counter = make_counter();
    println!("{}", counter());  // 1
    println!("{}", counter());  // 2
}

Iterators ​

Creating Iterators ​

rust
fn main() {
    let v = vec![1, 2, 3, 4, 5];

    // .iter() — borrows elements (&T)
    for item in v.iter() {
        println!("{item}");  // item is &i32
    }

    // .iter_mut() — mutable borrows (&mut T)
    let mut v = vec![1, 2, 3];
    for item in v.iter_mut() {
        *item *= 2;  // item is &mut i32
    }

    // .into_iter() — takes ownership (T)
    let v = vec![1, 2, 3];
    for item in v.into_iter() {
        println!("{item}");  // item is i32
    }
    // v is gone — consumed by into_iter()

    // Range iterators
    for i in 0..5 { }      // 0, 1, 2, 3, 4
    for i in 0..=5 { }     // 0, 1, 2, 3, 4, 5
    for i in (0..5).rev() { }  // 4, 3, 2, 1, 0
}

Iterator Adaptors (Lazy) ​

rust
fn main() {
    let v = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

    // map — transform each element
    let doubled: Vec<_> = v.iter().map(|x| x * 2).collect();

    // filter — keep matching elements
    let evens: Vec<_> = v.iter().filter(|&&x| x % 2 == 0).collect();

    // enumerate — add index
    for (i, val) in v.iter().enumerate() {
        println!("{i}: {val}");
    }

    // zip — combine two iterators
    let a = [1, 2, 3];
    let b = ["one", "two", "three"];
    let zipped: Vec<_> = a.iter().zip(b.iter()).collect();
    // [(1, "one"), (2, "two"), (3, "three")]

    // chain — concatenate iterators
    let first = [1, 2, 3];
    let second = [4, 5, 6];
    let all: Vec<_> = first.iter().chain(second.iter()).collect();

    // flat_map — map then flatten
    let words: Vec<&str> = vec!["hello world", "foo bar"]
        .iter()
        .flat_map(|s| s.split_whitespace())
        .collect();
    // ["hello", "world", "foo", "bar"]

    // take and skip
    let first_three: Vec<_> = v.iter().take(3).collect();
    let after_three: Vec<_> = v.iter().skip(3).collect();

    // take_while and skip_while
    let small: Vec<_> = v.iter().take_while(|&&x| x < 5).collect();

    // peekable — look ahead without consuming
    let mut iter = v.iter().peekable();
    if let Some(&&first) = iter.peek() {
        println!("First will be: {first}");
    }
}

Consumers (Eager) ​

rust
fn main() {
    let v = vec![1, 2, 3, 4, 5];

    // collect — gather into a collection
    let doubled: Vec<i32> = v.iter().map(|x| x * 2).collect();

    // sum, product
    let total: i32 = v.iter().sum();
    let product: i32 = v.iter().product();

    // count
    let even_count = v.iter().filter(|&&x| x % 2 == 0).count();

    // any, all
    let has_even = v.iter().any(|&x| x % 2 == 0);
    let all_positive = v.iter().all(|&x| x > 0);

    // find — first matching element
    let first_even = v.iter().find(|&&x| x % 2 == 0);  // Some(&2)

    // position — index of first match
    let pos = v.iter().position(|&x| x == 3);  // Some(2)

    // min, max
    let smallest = v.iter().min();  // Some(&1)
    let largest = v.iter().max();   // Some(&5)

    // fold — accumulate with initial value
    let sum = v.iter().fold(0, |acc, &x| acc + x);
    let sentence = ["hello", "world"].iter()
        .fold(String::new(), |acc, &word| {
            if acc.is_empty() { word.to_string() }
            else { format!("{acc} {word}") }
        });

    // for_each — side effects
    v.iter().for_each(|x| println!("{x}"));
}

Chaining Example ​

rust
fn main() {
    let data = vec![
        ("Alice", 85),
        ("Bob", 92),
        ("Charlie", 78),
        ("Diana", 95),
        ("Eve", 88),
    ];

    // Complex iterator chain
    let honor_roll: Vec<String> = data
        .iter()
        .filter(|(_, score)| *score >= 90)
        .map(|(name, score)| format!("{name}: {score}"))
        .collect();

    println!("Honor roll: {honor_roll:?}");
    // ["Bob: 92", "Diana: 95"]
}

Implementing Iterator ​

rust
struct Countdown {
    value: u32,
}

impl Countdown {
    fn new(start: u32) -> Self {
        Countdown { value: start }
    }
}

impl Iterator for Countdown {
    type Item = u32;

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

fn main() {
    for n in Countdown::new(5) {
        println!("{n}");  // 5, 4, 3, 2, 1
    }

    // All iterator methods work automatically
    let sum: u32 = Countdown::new(5).sum();  // 15
}

Built with VitePress | Rust SOP Documentation