Why an additional mut keyword is required in closure?

fn main() {
    let mut list = vec![1, 2, 3];
    println!("Before defining closure: {:?}", list);

    let mut borrows_mutably = || list.push(7);

    borrows_mutably();
    println!("After calling closure: {:?}", list);
}

Why an addition mut key word is required here.

    let mut borrows_mutably = || list.push(7);

If you look at the FnMut trait that this closure works with

you'll notice that it's call method is a (&mut self) method. Hence the closure must be marked mutable.

You closure doesn't actually mutate itself on the call, other FnMut closures can do this though, like say a closure that captures a variable by-value and mutate it inside.

However, even your closure needs exclusive access to what's being captured. Exclusive access can, in Rust, be modeled across function / abstraction boundaries only via mutable access. Rust's reference types are "shared, immutable references" and "unique, mutable references" and of the two only the latter gives you uniqueness, so it sometimes means you have to mark a few more things as mutable just to get the uniqueness you need.

1 Like

The compiler infers the type of the closure to be FnMut, since it considers that you might call borrows_mutably more than once.

If you want to change this, convince the compiler that you will call it only once:

fn main() {
    let mut list = vec![1, 2, 3];
    println!("Before defining closure: {:?}", list);

    let borrows_mutably = || list.push(7);
    
    receives_callback(borrows_mutably);
    
    println!("After calling closure: {:?}", list);
}

fn receives_callback(callback: impl FnOnce() -> ()) {
    callback()
}

Incidentally... another way to get unique access, though even more restrictive, is owned access. Any FnOnce closure can thus be called without the closure marked mut. Even your FnMut closure here can work this way if you force a move at the call site. One way to do this is with a block expression. E. g. this compiles:

fn main() {
    let mut list = vec![1, 2, 3];
    println!("Before defining closure: {:?}", list);

    let borrows_mutably = || list.push(7);

    ({ borrows_mutably })();
    println!("After calling closure: {:?}", list);
}
1 Like