1

I have what I think to be a simple question, but not much luck finding an answer for it.

Background

I understand the difference between Fn and FnMut in Rust, but I see quite often the need to accept closures that require a 'static lifetime bound.

The Question

Is an Fn() + 'static equivalent to FnMut() + 'static?

My Opinion

In my opinion, I seem to believe they are, because an Fn allows for capturing immutable references to its environment, whereas FnMut, mutable references, however, due to the 'static lifetime bound, the only references they can have, are owned ones, and therefore will almost always have move semantics associated with the closure. Since only owned values, or special &'static references can have 'static lifetime, it seems to me pointless to want to have or need an FnMut() in this case, since there is no mutable reference one might be able to get to the closures environment.

Am I wrong with this conclusion? My guess is yes, otherwise there would probably be a Clippy lint for this.

Acorn
  • 24,970
  • 5
  • 40
  • 69
Jose Quesada
  • 417
  • 3
  • 6
  • 4
    I think you're wrong. `FnMut` can mutate the values it *captures*, which `Fn` can't. Yes, both typically own the captured values (although they can refer to static borrowed data as well), but the latter means that you can invoke `Fn` from multiple threads (if it's also `Sync`), which you can't do with `FnMut`. – user4815162342 Feb 10 '22 at 16:06
  • 1
    To illustrate @user4815162342's point, this [playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=f212056698fba0fe420aff9d672357e1) shows the difference. – rodrigo Feb 10 '22 at 16:28
  • Does this answer your question? [How can a closure using the `move` keyword create a FnMut closure?](https://stackoverflow.com/q/50135871/3650362) – trent Feb 10 '22 at 16:50
  • Also possibly relevant: [When does a closure implement Fn, FnMut and FnOnce?](https://stackoverflow.com/q/30177395/3650362) and [The compiler suggests I add a 'static lifetime because the parameter type may not live long enough, but I don't think that's what I want](https://stackoverflow.com/q/40053550/3650362) (the `'static` bound here does not mean "contains some `&'static` reference") – trent Feb 10 '22 at 16:52

1 Answers1

4

Any closure type can capture any kind of data. The difference is how the closure can access the captured data while it is executed. An Fn closure receives a shared reference to its captured data. An FnMut closure receives a mutable reference to its captured data, so it can mutate it. And finally, an FnOnce closure receives ownership of the captrued data, which is why you can call it only once.

The 'static trait bound means that the captured data has static lifetime. This is completely orthogonal to the question what a closure can do with its captured data while it is called.

Sven Marnach
  • 574,206
  • 118
  • 941
  • 841