12.7 Additional Topics

12.7.1 Assigning Functions to Variables

In Rust, you can assign function pointers to variables, but functions and closures are different types.

Assigning a Function to a Variable:

#![allow(unused)]
fn main() {
fn add(x: i32, y: i32) -> i32 {
    x + y
}

let add_function: fn(i32, i32) -> i32 = add;
let result = add_function(2, 3);
println!("Result: {}", result); // Output: Result: 5
}
  • The type of add_function is fn(i32, i32) -> i32.
  • Functions cannot capture variables from the environment.

Differences Between Functions and Closures:

  • Functions: Cannot capture environment variables; have a concrete type.
  • Closures: Can capture environment variables; have unique anonymous types.

12.7.2 Returning Closures

Returning closures from functions requires using trait objects or generics.

Using Trait Objects:

#![allow(unused)]
fn main() {
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
    Box::new(|x| x + 1)
}
}
  • Requires heap allocation.

Using Generics (with impl Trait):

#![allow(unused)]
fn main() {
fn returns_closure() -> impl Fn(i32) -> i32 {
    |x| x + 1
}
}
  • No heap allocation; the closure type is concrete but anonymous.

12.7.3 Closure Examples in Real-World Applications

  • Event Handlers: GUI applications use closures to handle events.
  • Asynchronous Programming: Futures and async code often use closures for callbacks.
  • Configuration: Passing closures to configure behavior dynamically.