Core Concept: Closures & Iterators ​
Updated Mar 2026Overview ​
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
}