Compiles when FnMut is initially immutable?

fn a<F: FnMut()>(mut f: F) {
    f()
}
fn main() {
    let mut n = 0u8;
    let f = || n += 1;
    a(f);
    println!("{n}")
}

In the main function, I used "let" statement but not "let mut" to initialize the closure, why does it compile when f is initialized by "let" and function a takes a mutable closure?

Because the f in main is being moved into the a(f) call. You don't have to declare a variable as mutable in order to move out of it.

4 Likes

Is that closure allocated on heap?

No, you need to have it behind a heap pointer like Box to have it on the heap. Rust generally doesn't do implicit allocations.

1 Like

If you want a simpler example of the phenomenon...

fn main() {
    let s1 = "Hello".to_string();
    let mut s2 = s1;
    s2.push_str(", world!");
    println!("{s2}");
}

Using let var ... instead of let mut var ... will prevent you from

  • Creating a &mut _ to var
  • Overwriting var once it has been initialized

But it doesn't prevent other uses, it doesn't prevent moving var, it doesn't change the type of var, and it doesn't reflect any intrinsic immutability about values/data stored in var.

(In contrast, &T and &mut T are distinct types with significantly different properties.)

5 Likes

let mut doesn't control whether a value is mutable. Every owned value can be mutated.

This is perfectly legal in Rust:

let x = new();
let mut x = x;
x.mutate();

and this too:

let x = new();
{x}.mutate();

let mut is only a shallow lint for "did you mean to reassign this variable?" and "did you meant o use &mut methods directly on this variable?". It's technically optional from perspective of Rust's semantics, and doesn't affect compiled code. Mutations of the value can happen anyway, and the let vs let mut distinction of a variable stops affecting the value behind it as soon as the value is moved to another place.

2 Likes

How is that relevant? It doesn't matter at all for mutability and ownership whether a value is on the stack or the heap. They are completely orthogonal.