Skip to content
Select theme

Why does Rust require the mut keyword?

Short answer: let makes a binding you cannot reassign. Write let mut count = 0 when you need to change the value after the binding is created. mut doesn’t change the type of anything — it’s a property of the binding, not of the value.

cargo build prints:

error[E0384]: cannot assign twice to immutable variable `count`
--> src/main.rs:3:5
|
2 | let count = 0;
| -----
| |
| first assignment to `count`
| help: consider making this binding mutable: `mut count`
3 | count = count + 1;
| ^^^^^^^^^^^^^^^^^ cannot assign twice to immutable variable
For more information about this error, try `rustc --explain E0384`.

The message says “assign twice” even though you assigned once after the initialiser — and the diagnostic points at both lines. The let counts as the first assignment, so the reassignment is the second.

count = 2

(+= 1 is the same as count = count + 1; it’s the reassignment that needs the mut, not the operator.)

mut belongs to the variable name, not to the type. let x: i32 and let mut x: i32 are both i32, and the type checker sees no difference between them: all you’ve declared is that this particular name may be assigned to again.

The same is true of a mut in a parameter list:

42
21 is unchanged

double reassigns its copy of n as much as it likes. From the outside it’s an ordinary fn(i32) -> i32 — the mut is part of the body, not the signature, and the caller’s let n = 21 needs no mut of its own.

Reassignment is the obvious case. The other one is calling a method that changes the value:

error[E0596]: cannot borrow `numbers` as mutable, as it is not declared as mutable
--> src/main.rs:3:5
|
3 | numbers.push(4);
| ^^^^^^^ cannot borrow as mutable
|
help: consider changing this to be mutable
|
2 | let mut numbers = vec![1, 2, 3];
| +++
For more information about this error, try `rustc --explain E0596`.

Vec::push needs a mutable receiver, so the binding has to be declared mutable before the call is even considered:

[1, 2, 3, 4]

A binding that can’t change is one the reader can rely on. Leaving mut off tells whoever opens the function next that nothing below reassigns this name — in code you didn’t write, that’s one less thing to trace.

So write let, and add mut only where the compiler asks for it. Both errors above are the compiler asking. Sprinkling mut on every binding to pre-empt them costs you that signal and buys nothing.