While studying The Book today, I got confused about why Listing 16-12 is allowed to mutate the value of m
despite m
being declared without the mut
keyword:
use std::sync::Mutex;
fn main() {
let m = Mutex::new(5); // Lacks the `mut` keyword here
{
let mut num = m.lock().unwrap();
*num = 6;
}
println!("m = {m:?}");
}
The Book: Listing 16-12: Exploring the API of Mutex<T>
in a single-threaded context for simplicity (Comment added for emphasis)
That code prints the following to Standard Output:
m = Mutex { data: 6, poisoned: false, .. }
This shows that the value of m
's data
field got mutated from 5
to 6
, despite m
being declared without the mut
keyword.
This is in contrast to the concept expressed in Section 3.1 of The Book, which says that variables are immutable by default, and that it is important for mutable variables to have the mut
keyword in front of the variable name if the value is subject to change.
For example, if I try running the following code, the compiler will reject it, as I am trying to mutate a non-mut
variable's value:
fn main() {
let a = 5; // Again, no `mut` keyword, but the compiler won't be happy this time
let b = &mut a;
*b = 10;
println!("{}", b);
}
I rightfully get the following error in this second scenario:
Compiling playground v0.0.1 (/playground)
error[E0596]: cannot borrow `a` as mutable, as it is not declared as mutable
--> src/main.rs:3:13
|
3 | let b = &mut a;
| ^^^^^^ cannot borrow as mutable
|
help: consider changing this to be mutable
|
2 | let mut a = 5; // Again, no `mut` keyword, but the compiler won't be happy this time
| +++
For more information about this error, try `rustc --explain E0596`.
error: could not compile `playground` (bin "playground") due to 1 previous error
I was puzzled over this. How could we let Mutex
get away with not having to follow the same rules as the other variable types?
As I kept reading, however, I eventually found that the answer has to do with interior mutability. This is because Mutex<T>
provides interior mutability, as the Cell
family does. I'm still in the process of trying to figure out more about the motivation/reasoning behind interior mutability, but I at least have a starting point now.
I would love to hear your thoughts on the advantages of interior mutability (as opposed to regular mutability), and why the normal requirement for an explicit mut
declaration is deliberately waived for cases of interior mutability.
Hopefully this post helps someone who is scratching their head (like I was) to be able to have their "Oh, that's why" moment a little sooner.
When something is confusing, keep reading! 

3 posts - 3 participants
Read full topic
🏷️ rust_feed