12.4 Performance Considerations

Rust closures provide strong performance characteristics:

  • No Hidden Heap Allocations: Closure objects (the implicit struct holding captured data) typically live on the stack if their size is known at compile time. They are not automatically heap-allocated unless explicitly placed in a Box or other heap-based container.
  • Zero-Cost Abstraction (Generics): When closures are passed using generics (impl Fn...), the compiler performs monomorphization, generating specialized code for each closure type. This allows inlining the closure body, resulting in performance equivalent to a direct function call. There is usually no runtime overhead.
  • Dynamic Dispatch (dyn Fn...): Using trait objects (Box<dyn Fn()>, &dyn FnMut(), etc.) allows storing different closure types together but introduces:
    • A small runtime cost for vtable lookup (like C++ virtual functions).
    • Heap allocation if using Box<dyn Fn...>. This offers flexibility at the expense of some performance.

For performance-critical code, prefer generics (impl Fn...) over trait objects (dyn Fn...) to leverage static dispatch and inlining.