Baffled By The Borrow Checker

The compiler determines which Fn* trait a closure implements by analyzing how the closure body uses the captures in its environment. If the closure moves and drops any of its captures, then it can only implement FnOnce. If it only uses its captures as &mut T, then it can implement FnMut. If it only uses its captures as &T, then it can implement Fn. [1]

There is some real subtlety, here! move closures do not control which trait is implemented. Only how the captures are used influences it. This point came up a short while ago in another thread:


In short, no! As explained by others, Option::take() only moves the inner T out of the Option. The Option itself doesn't get dropped. If it did, that would make the closure implement FnOnce instead of FnMut. Just like the demonstration closures in the playground.


  1. Note that the closure does not have to use all of its captures in these ways. The trait that gets implemented (by the compiler) is selected by the capture use that has the most restriction. Even if most captures are used by &T, just one use by &mut T of any capture will make the closure FnMut. If that makes sense... ↩︎

1 Like