mutability (or the ability to change something) is not a default
let x = 5;
x = 6; // ERROR!!
but with mut
let mut x = 5;
x = 6; // no problem
the x
variable has a full name of "mutable variable binding" in Rust
when a binding in mutable, you can change what the binding is pointing to.
so in the last example above: the value of x is not changing, it's just pointing to a new i32
.
you can also create a reference to a binding
let mut x = 5;
let y = &mut x;
but if you want to use the reference to change it (write; not just read):
you need a mutable reference: &mut
y
is an immutable binding to a mutable reference. so you can't change what y is pointing to like: y = &mut z;
but you can edit the x
's value like this: *y = 5;
(accessing x's value by dereferencing)
but if you need both;
let mut x = 5;
let mut y = &mut x;
the use of mut
is part of a pattern.
so it's uses are pretty widespread:
let (mut x, y) = (5, 6);
fn foo(mut x: i32) {}
this comparison and difference boils down to:
the real definition of immutability: is this safe to have two pointers to?
take this for example:
use std::sync::Arc;
let x = Arc::new(5);
let y = x.clone();
when we call clone(), Arc
needs to update the reference count (Arc is just a reference counter.)
Arc is able to hand out a reference (&T) to y with clone()
but if it handed out &mut T
then there would be a problem.
but here is an example of interior mutability
use std::cell::RefCell;
let x = RefCell::new(42);
let y = x.borrow_mut();
in this case RefCell
hands out a &mut
but if you tried to use x.borrow_mut
again with new variable binding then the program would panic!
RefCell
enforces Rust's borrowing rules at runtime, and panic's if they're violated.
mutability is either a property of a borrow (&mut T) or a binding (let mut).
for example you cannot have a immutable and mutable field inside a struct definition.
struct Point {
x: i32,
mut y: i32, // Nope this will not compile
}
the mutability of a struct is in it's binding:
struct Point {
x: i32,
y: i32,
}
let mut a = Point { x: 5, y: 6 };
a.x = 10;
let b = Point { x: 5, y: 6 };
b.x = 10; // Error: cannot assign to immutable field `b.x`.
however by using Cell, you can emulate field-level mutability
use std::cell::Cell;
struct Point {
x: i32,
y: Cell<i32>,
}
let point = Point { x: 5, y: Cell::new(6) };
point.y.set(7);
println!("y: {:?}", point.y);