Why is the function mutably borrowed in this example?

Hello,

The following example is adapted from the definition of Iterator::find in the standard library. This doesn't compile because predicate is immutable:

fn check<T>(predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> bool {
    move |x| predicate(&x)
}

// error[E0596]: cannot borrow `predicate` as mutable, as it is not declared as mutable

The error is resolved by declaring predicate as mutable, as the standard library does:

fn check<T>(mut predicate: impl FnMut(&T) -> bool) -> impl FnMut(T) -> bool {
    move |x| predicate(&x)
}

Why can't the closure call predicate without mutably borrowing it? Does the call cause any mutation in the value of predicate?

Thank you!

FnMut has signature fn call(&mut self, ...args) so by definition calling it borrows it. It's called FnMut for a reason. You can change it to Fn to see the difference.

2 Likes

With FnMut, any variables captured by the closure can be mutated by the closure. So the closure itself must be mutable.

Internally, a struct is created for a closure to contain the captured variables. In the generated code, a hidden self parameter is used to refer to the captured variables in this struct. For FnMut, &mut self is used. For Fn, &self is used. And for FnOnce, self is used; this means self is consumed which is why it can only be called once.

See the example here:
https://doc.rust-lang.org/reference/types/closure.html

And more general info here:
https://doc.rust-lang.org/book/ch13-01-closures.html

3 Likes

Thank you for the explanation, understanding the implementation here is illuminating.