The mut
keyword has a different meaning when qualifying the mutability of a reference and the mutability of a binding.
When the mut
keyword appears to the left of the =
sign, it qualifies the mutability of the binding. The binding is not the value itself, it is a way of accessing the value.
A mutable binding allows to reassign the value it is bound to, modify it and take a mutable borrow to that value. It says nothing about the mutability of the underlying value. As others noted, this meaning is primarily intended to allow the developer to express their intent of mutating a variable through a binding, so that the compiler can emit messages when the actual code diverge from the expressed intent (e.g., when you mutate a variable through a binding that was not denoted as mutable, or when you don't mutate a variable through a binding that was denoted as mutable). Note that this lint is useful in practice, and caught numerous bugs for me in the past while developing (such as instantiating a mut binding and forgetting to mutate it before returning its value).
When the mut
keyword appears to the right of the =
sign (and of the &
sign), it qualifies the mutability of the reference.
A mutable reference allows to reassign the referenced value, modify it, and (mutably or immutably) reborrow it. It also guarantees that the value will not mutate through any other reference of through the owner while the mutable reference is alive (and in the absence of interior mutability). As others also noted, this meaning is integral to the "ownership system" of rust and cannot really be removed.
Your proposition of having mut qualify a value would be a third meaning to that keyword. And I can see a world where it would make sense! But in the timeline we are in, rust doesn't have immutable values. As such, it wouldn't make sense to mark a value as mut
, because all of them are! It is not useful to express "immutably owns" and "mutably owns", because everyone always "mutably owns", so we just say "owns".
In particular, this means that even if you pass an owned value to a function through an immutable binding, the function will be able to modify the owned value it now owns, simply by rebinding the value to a new, mutable binding:
fn mutate_owned(owned /* immutable binding */: String) -> String {
let mut owned = owned; // rebind the value with a mutable binding
owned += &" mutated"; // OK on a mutable binding
return owned
}
This is not really surprising: after all, the function now owns the value, it is logical that it could do anything with it, including modifying it.
Similarly, I sometimes use the ability to shadow existing bindings in rust to express "areas where a variable will be mutated", using mutable and immutable bindings:
let x = String::from("some string"); // x won't be mutated right away
if not validate_string(&x) {
return WrongFormatError; // Note: could use ? operator here to be more idiomatic
}
let mut x = x; // serious business now, we will mutate x
encode_string(&mut x);
// ... some other logic
let x = x; // all operations from now on won't modify x, except if it is rebound again.
// ... some other logic
println!({}, x);
Note that you don't have to rebind all bindings immutably as soon as you are done mutating them or mutably just for the short time where you want to mutate them, it might be OK to have a single mutable binding in the code above. But the ability to rebind variables can come in handy in certain scenarios.