First, move means capture by value instead of by reference. That is, the values are moved into the closure and go where it goes. You can’t freely move around a non-move closure because it references the stack.
Basically, a move closure’s environment (or receiver as you’ll see below) looks like:
struct EnvMove {
variable1: Type1,
variable2: Type2,
}
and a non-move closure’s environment looks like:
struct EnvRef<'a> {
variable1: &'a Type1, // Note: this will be `&'a mut` if an `&mut` reference to `variable1` is used in the closure.
variable2: &'a Type2,
}
As for the Fn* traits, take a look at the signature of the call method in the respective traits:
|:| -> FnOnce::call_once(self, ...)
|&:| -> Fn::call(&self, ...)
|&mut:| -> FnMut::call_mut(&mut self, ...)
The receiver, self, is the environment. A closure is just sugar for defining a struct to contain the environment (EnvRef or EnvOwn) and implementing one of the Fn traits on it.
Use cases:
- Use
FnOnce if you need to move variables out of the closure (consume the environment).
- Use
Fn if you need to reference the environment but don’t need to mutate it.
- Use
FnMut if you need to mutate the environment.
So you would use move |&:| / move |&mut:| if you want to be able to give away a closure that can be called multiple times. The limitation is that this closure can’t move anything out of itself.