In the below code snippet, the value of variable s has moved into closure.
Does that mean closure is now FnOnce? If yes, how can I call closure more than once?
let s = String::from("");
let closure = move || s.len();
closure(); // ok
closure(); // ok
println!("{s}"); // error - borrow of moved value: `s`
I removed the method call len() and then it allowed me to call closure only once. Not sure how this works.
The move keyword determines what happens when the closure is created. This move happens only once, regardless of what you later do with the closure.
The closure’s body determines what happens when the closure is called.
If the body only calls methods like s.len() that borrow the string immutably, then it will implement the Fn trait (can call many times, via shared reference).
If it instead calls methods like s.clear() that borrow the string mutably, then it will implement the FnMut trait (can call many times, but only via exclusive &mut reference).
If it runs code that consumes or destroys s (like drop(s) or just s;) then it will only implement the FnOnce trait (can only call once, requires ownership).
Some inferences based on the closure body, including which Fn* traits are implemented, can also be influenced by creating the closure in the context that is annotated with a Fn* trait bound. Typically that context is the argument of a function call.
So here, the closure can't be a FnMut because closures can't return reborrows of their fields. But based on the closure body alone, the compiler thinks that's what you want, so it attempts the FnMut implementation and shows you the reason it can't work as an error. But if you pass it to the function, the compiler only implements FnOnce, and that's fine because you can give away the entire &mut _ once.
And here, when the closure is defined in a FnMut context, the compiler doesn't implement Fn() even though it could.
Note that dropping or otherwise moving values with types that implement Copy does not consume/destroy the value, and thus doesn't inhibit FnMut or Fn. (And closures themselves implement Copy if able to.)