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

but here's the distinction;

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) {}

Interior vs Exterior Mutability


this comparison and difference boils down to:

The Reference rules from borrowing:

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.

Field-Level Mutability


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);