When I learn Rust's mut
keyword and references types, everything seemed logical.
Basicly without mut
decleared, any member of a struct cannot change.
Until I read to this: https://doc.rust-lang.org/rust-by-example/fn/closures/capture.html
let mut count = 0;
// A closure to increment `count` could take either `&mut count` or `count`
// but `&mut count` is less restrictive so it takes that. Immediately
// borrows `count`.
//
// A `mut` is required on `inc` because a `&mut` is stored inside. Thus,
// calling the closure mutates the closure which requires a `mut`.
let mut inc = || {
count += 1;
println!("`count`: {}", count);
};
// Call the closure using a mutable borrow.
inc();
The inc
closure get a &mut count
, and use it to update count
.
I think while updating count
, the &mut count
is not modified.
So inc
should be immutable.
The explanation doesn't make sence, I don't think "calling the closure mutates the closure".
I cannot figure out what changed of the int
closure.
After Google, I read: https://internals.rust-lang.org/t/closure-value-moved-why-mut-needed/11082/16 https://www.reddit.com/r/rust/comments/8gbp22/explanation_struct_with_mutable_reference_field/
Those discussion help a little, but I finally understand by myself.
A mut
value can only be access by one vairable at a time. Either a "owner" or a "mut reference".
If we pass a &mut
to another struct, we should also make sure when using that &mut
field,
it also can only be access by one vairable at a time.
So with a shared reference(&) to this another struct access to its &mut
field is not allowed.
Because shared reference can be mutiple.
That leave us two options: with "owner" vairable or "&mut".
With "owner" vairable, it looks reasonable. Like this:
let foo = Foo {
hold_mut_ref: &mut value,
};
*(foo.hold_mut_ref) += 1;
foo
is immutable, no mut
keyword needed.
With "&mut", it looks rediculous. Like this:
let mut value = 0;
let mut foo = Foo {
hold_mut_ref: &mut value,
};
let ref_foo = &mut foo;
*ref_foo.hold_mut_ref += 1;
foo
itself doesn't changed, but it need to be mark mut
.
The only reason for foo
need mut
is to make sure foo cannot be borrowed twice,
which may lead to hold_mut_ref
be borrowed twice, which lead to multiple mutable borrowing.
The key to this question is to accept that 'mut' keyword is not only for allowing mutate the value being marked, but also for making sure only one reference can access to the value at a time.
Back to inc
closure, inc
closure captures a &mut
. If we can call inc
with "owner" variable,
inc
doesn't need to be mut
. But calling a closure is through reference by compiler design.
So for same reason as Foo
above, calling closure is calling FnMut
trait, which need a &mut self
,
for locking the &mut
captured by it.
Maybe mut
should rename to lock
. Because immutable data is thread safe without any lock.
The only reason we need a lock is to mutate data.