Rust - Closures

Overview

Estimated time: 60–75 minutes

Master Rust's powerful closure system for functional programming. Learn capture modes, the Fn trait family, and how to use closures effectively in real-world applications.

Learning Objectives

Prerequisites

What are Closures?

Closures are anonymous functions that can capture variables from their enclosing environment. They're more flexible than regular functions and enable powerful functional programming patterns.

Basic Closure Syntax


fn main() {
    // Basic closure syntax
    let add = |a, b| a + b;
    println!("Add: {}", add(5, 3));
    
    // Closure with explicit types
    let multiply: fn(i32, i32) -> i32 = |a, b| a * b;
    println!("Multiply: {}", multiply(4, 7));
    
    // Closure with block body
    let complex_operation = |x: i32| {
        let doubled = x * 2;
        let squared = doubled * doubled;
        squared + 1
    };
    println!("Complex: {}", complex_operation(3));
    
    // Closure that captures environment
    let factor = 10;
    let scale = |x| x * factor;  // Captures 'factor'
    println!("Scaled: {}", scale(5));
}

Expected output:

Add: 8
Multiply: 28
Complex: 37
Scaled: 50

Checks for Understanding

Question 1: Capture Modes

Q: What's the difference between a closure with and without the move keyword?

Click to see answer

A: Without move, closures capture variables by reference (borrowing). With move, closures take ownership of captured variables, moving them into the closure's environment.

Question 2: Fn Traits

Q: If a closure mutates a captured variable, which Fn trait does it implement?

Click to see answer

A: FnMut - because it needs mutable access to its environment. It can be called multiple times but requires a mutable reference to self.

Question 3: Returning Closures

Q: Why do we need Box<dyn Fn()> when returning closures from functions?

Click to see answer

A: Each closure has its own unique type that's generated by the compiler. To return different closures from the same function, we need dynamic dispatch with trait objects, and Box provides heap allocation for the varying-sized closure types.


← PreviousNext →