Rationale behind Fn, FnMut and FnOnce design

The simplest way to show concurrency is through parallelism, so you'll mainly see three kind of closures:

  • FnOnce(), for "the callee will need to call the callback at most once" kind of situations, which allows the closure to be optimized by consuming its captured environment when called. Std lib examples:

  • FnMut() for something that is callable multiple times sequentially / non-concurrently.
    Stdlib examples:

    • the whole plethora of Iterator adaptors / consumers

    • Sometimes with Send and/or 'static bounds for things called from another thread or abitrarily late respectively.

  • Fn() + Sync, for something callable in parallel (Fn() -> callable concurrently / through multiple / shared handles; Sync -> these handles can cross thread boundaries. Hence why it can be called from multiple threads at once). In practice, there are also + Send + 'static bounds, since the moment multiple threads are involved, the "end of life" flows can rarely be guaranteed at compile-time, which thus requires 'static bounds and dynamic / multiple ownership, e.g., Arcs.

    • Comparatively to the previous batch of stdlib single-threaded / sequential iterator adaptors which take FnMuts, ::rayon's own set of iterator adaptors / consumers which feature that Fn… + Sync (+ Send) bounds.

But for the sake of the example, you could, quite rarely, see a non-Sync Fn requirement, such as some thread-local hook: since the hook could technically be triggered when the very hook is being run (re-entrancy, another form of concurrency which happens not to require multi-threading to happen), then such a hook would need to be Fn().


If by sharing you mean sharing-and-using, then yes, Rust will prevent it, and that's the whole point about Rust, although not limited to Fn…s: if you are sharing something, you only get & access to it, and thus only have access to the &shared-compatible parts of that element's API, such as the &self-based methods. Calling a Fn is such as method.

If you are not sharing, then you can get a &unique access to it (dubbed &mut in Rust), and thus can use the stronger but more restrictive parts of the item's API: the &mut-based functions, such as &mut self methods, which includes calling a FnMut.


Indeed, and that's a code smell since it's "as useful as nipples on a breastplate": Sync allows &shared access to cross threads, but FnMut requires &unique access to be callable, so while you may be sending &shared-access-yielding handles across threads, you'll never be calling that FnMut().