Mutation in Rust: Before or After the Colon? An Under-the-Hood Analysis

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Introduction: The Mystery of Two "mut"s

\n

If you've ever written in Rust, you've likely noticed the strange duality of the keyword mut. It can appear both before a variable name (let mut x = 5) and after the colon, next to the type (&mut T). At first glance — a small detail, but on Stack Overflow this topic has gathered thousands of views. Why? Because behind this small detail lies a fundamental difference between ownership and reference.

\n

In this article, we won't just answer the question "where to put mut?". We'll look under the hood of Rust, break down how the compiler handles mutability, and why this distinction is the key to safe memory management. If you're learning Rust or want to deepen your understanding of its ownership model — you're in the right place.

\n\n

Main Part: Two Worlds — Two muts

\n

1. The First mut: "I am the owner and I can change"

\n

When you write:

\n
let mut x = 42;\nx = 10; // ok\n
\n

you are telling the compiler: "I am creating a variable x that owns the value 42, and I allow changing this value later." Without mut, the variable is immutable by default. This is a deliberate design choice in Rust: safety by default, and mutation is an explicit permission.

\n

Under the hood: The compiler allocates space on the stack (or heap, if it's a Box) and marks the memory cell as "mutable". The borrow checker will ensure you don't have both mutable and immutable references to this memory simultaneously. If mut were not present, any attempt to assign a new value would cause a compilation error.

\n\n

2. The Second mut: "I give you the keys, but not the house"

\n

Now an example with a reference:

\n
let mut x = 42;\nlet y = &mut x; // mutable reference to x\n*y = 100;\n
\n

Here, &mut T is not about ownership, but about borrowing. We are saying: "I am lending x to variable y, and I give it the right to change it." x itself remains the owner, but temporarily transfers control.

\n

Key difference: mut after the colon refers to the type of the reference, not the variable. You cannot write let &mut x = &y — it's syntactically incorrect. Rust strictly distinguishes between:

\n
    \n
  • let mut x — a mutable owner variable
  • \n
  • &mut T — a mutable reference to some value of type T
  • \n
\n

It is precisely this distinction that confuses beginners: visually, "mut" appears in different places, but semantically, it solves different tasks.

\n\n

3. Why This Matters: The Borrow Checker

\n

Imagine you write a function that takes a reference:

\n
fn increment(n: &mut i32) {\n    *n += 1;\n}\n\nfn main() {\n    let mut a = 5;\n    increment(&mut a);\n    println!("{}", a); // 6\n}\n
\n

If we had written fn increment(n: &i32) (without mut), we wouldn't be able to change n. And if we forgot mut on a, we wouldn't be able to pass a mutable reference. The Rust compiler protects you from accidentally modifying data, which could lead to data races or undefined behavior.

\n

Under the hood: &mut T is a unique (exclusive) reference. At any given time, only one mutable reference to the data can exist. This rule guarantees that no one else is reading the data while you are changing it. There can be any number of immutable references — they only read.

\n\n

4. Real-World Example: Structs and Methods

\n

Confusion often arises when working with methods:

\n
struct Point {\n    x: i32,\n    y: i32,\n}\n\nimpl Point {\n    fn shift(&mut self, dx: i32, dy: i32) {\n        self.x += dx;\n        self.y += dy;\n    }\n}\n\nfn main() {\n    let mu                

Blogs

Book Recommendations