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
isfn(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.