We could say that in Rust "everything is mutable", in that no matter the type, you could have a mutable "instance" / element of that type.
The choice Rust has made in that regard is to reason about mutability, not w.r.t. types, but w.r.t. particular instances / elements of that type. And actually it's something even more precise than that: the mutability applies to a binding, i.e. to a "variable name".
Consider the following example:
fn foo (s: String) // looks like s is immutable
let mut s2 = s; // change the name of the variable, and "enable" mutability under this new name
/* return */ s2
- An oversimplification to express this would be to say that "ownership implies mutability".
Now, you mention the
&mut ... type, and in the other direction, we could mention types such as
&str which would be "immutable".
The thing is, this confusion comes from being wave-handed regarding the definition of what is mutable.
Indeed, a variable / a type may be referring / pointing to some other place in memory. And Rust does encode the kind of access this pointer has:
owned (and usually exclusive), such as:
borrowed, but in an exclusive manner, such as
borrowed, but in a shared manner, such as
And for the borrowed, but in an exclusive manner, Rust allows us to mutate the pointee, hence (abusingly) calling it a "mutable reference".
Here is an example showcasing the difference between
mut p: &i32 and
p: &mut i32:
let mut x = 42;
let p = &mut x; // we get an exclusive borrow over `x` contents,
// we can thus mutate those:
*p = 0;
let x = 42;
let z = 0;
let mut p = &x; // shared borrow over `x` contents.
// Since it is shared, here the contents become immutable
// for the duration of the borrow.
// *p = 0; <- Error: we can't mutate the pointee
p = &z; // but `mut p` allows us to change `p` itself,
// _i.e._ we can change our pointer so that
// it points somewhere else:
assert_eq!(x, 42); // unchanged!
See this blog post about Rust mutation: To mut or not to mut.