I notice that Rust's Atomic*
structs have functions which modify the value, such as fetch_add
. For instance, I can write this program:
use std::sync::atomic::{AtomicUsize, Ordering};
struct Tester {
counter: AtomicUsize
}
impl Tester {
fn run(&self) {
let counter = self.counter.fetch_add(1, Ordering::Relaxed);
println!("Hi there, this has been run {} times", counter);
}
}
fn main() {
let t = Tester { counter: AtomicUsize::new(0) };
t.run();
t.run();
}
This compiles and runs fine, but if I change the AtomicUsize
to a normal integer, it will (correctly) fail to compile due to mutability concerns:
struct Tester {
counter: u64
}
impl Tester {
fn run(&self) {
self.counter = self.counter + 1;
println!("Hi there, this has been run {} times", self.counter);
}
}
It wouldn’t be very useful if it didn’t work this way. With &mut
references, only one can exist at a time, and no &
references at that time, so the whole question of atomicity of operation would be moot.
Another way of looking at it is &mut
are unique references, and &
aliasable references. For normal types, mutation can only safely occur if you have a unique reference, but atomic types are all about mutation (via replacement) without needing a unique reference.
The naming of &
and &mut
has been a fraught matter, with much fear, uncertainty and doubt in the community and documents like Focusing on Ownership explaining how things actually are. The language has ended up staying with &
and &mut
, but &mut
is actually about uniqueness rather than mutability (it’s just that most of the time the two are equivalent).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With