Comparison: impl Fn
vs Box<dyn Fn>
1. Using impl Fn
(Static Dispatch)
fn create_multiplier(factor: f32) -> impl Fn(f32) -> f32 {
move |value| value * factor
}
fn main() {
let multiply_by_4 = create_multiplier(4.0); // Closure that multiplies by 4
let result = multiply_by_4(9.0); // 9 * 4 = 36
println!("Result: {:?}", result); // Output: 36.0
}
Explanation:
create_multiplier
returns a closure that multiplies input by factor
.
impl Fn
tells the compiler to use static dispatch, which is efficient.
- The closure captures
factor
using move
.
2. Using Box<dyn Fn>
(Dynamic Dispatch)
fn create_dynamic_multiplier(factor: f32) -> Box<dyn Fn(f32) -> f32> {
Box::new(move |value| value * factor)
}
fn main() {
let multiply_by_4 = create_dynamic_multiplier(4.0); // Closure that multiplies by 4
let result = multiply_by_4(9.0); // 9 * 4 = 36
println!("Result: {:?}", result); // Output: 36.0
}
Explanation:
create_dynamic_multiplier
returns a boxed trait object (Box<dyn Fn>
).
- The closure is stored on the heap, allowing dynamic dispatch at runtime.
- Useful when flexibility is needed for different closure types.
Key Differences:
Feature | impl Fn (Static Dispatch) | Box<dyn Fn> (Dynamic Dispatch) |
---|
Dispatch Type | Compile-time (Static Dispatch) | Run-time (Dynamic Dispatch) |
Performance | Faster (No heap allocation) | Slower (Heap allocation + Indirection) |
Flexibility | Less flexible (Fixed closure type) | More flexible (Can store different types) |
Memory Usage | No heap usage | Uses heap (Boxed closure) |
Use Case | When closure type is known at compile time | When closure types may vary dynamically |
When to Use Each:
impl Fn
:
- When you know the closure type at compile time.
- Performance-critical code (no heap allocation).
Box<dyn Fn>
:
- When you need flexibility (e.g., storing multiple closures).
- Useful for dynamically created closures or heterogeneous collections.
Summary Example:
fn main() {
// Static dispatch: Fast and efficient
let static_multiplier = create_multiplier(3.0);
println!("Static Result: {}", static_multiplier(10.0)); // Output: 30.0
// Dynamic dispatch: More flexible
let dynamic_multiplier = create_dynamic_multiplier(2.5);
println!("Dynamic Result: {}", dynamic_multiplier(8.0)); // Output: 20.0
}