Rust Mutability and References: mut T, &T, &mut T, and mut &T

Author

Andres Monge

Published

May 13, 2026

Rust makes mutability explicit. This can feel strange when coming from Python or JavaScript, where variables and references are usually easier to reassign without much syntax.

A useful way to understand Rust is to separate two questions:

  1. Do I own the value, or am I borrowing it?
  2. Do I want to change the variable, the value, or neither?

That gives us four common patterns:

They look similar, but they mean different things.

mut T: I Own This Value and Want to Change It

Use mut T when you have a normal owned value and want to change it.

let mut score = 10;

score = 20;
score += 5;

println!("{score}");

Here, score is not a reference. It is the actual value. The mut means the variable can change.

You can also use it inside functions:

fn add_bonus(mut score: i32) -> i32 {
    score += 10;
    score
}

The function receives its own copy of the score, changes it locally, and returns the new value.

Use mut T when you want local state that you control.

&T: I Only Want to Read This Value

Use &T when you want to borrow a value without changing it.

fn print_name(name: &String) {
    println!("Hello, {name}");
}

This function does not own the String. It only borrows it.

let name = String::from("Andres");

print_name(&name);

println!("{name}");

Because print_name only borrowed name, the original variable can still be used after the function call.

Use &T when a function only needs to read something.

&mut T: I Want to Borrow This Value and Change It

Use &mut T when you want a function to modify a value without taking ownership of it.

fn add_exclamation(message: &mut String) {
    message.push('!');
}

Usage:

let mut greeting = String::from("hello");

add_exclamation(&mut greeting);

println!("{greeting}");

The function receives mutable access to the original String. It does not create a new one. It changes the existing value.

Rust requires this mutable borrow to be exclusive. While something has &mut T, Rust does not allow other active references to the same value.

This prevents bugs where two parts of the code try to read and write the same data at the same time.

Use &mut T when a function should update an existing value.

mut &T: I Want to Change Which Value I Am Looking At

This one is easy to misunderstand.

mut &T does not mean you can change the value being referenced.

It means the reference variable itself can point somewhere else.

let first = String::from("Alice");
let second = String::from("Bob");

let mut current: &String = &first;

println!("{current}");

current = &second;

println!("{current}");

Here, current first points to first, then points to second.

But current cannot modify either string.

// current.push('!'); // not allowed

So mut &T means:

I can change which value I am looking at, but I cannot change the value through this reference.

Use this when you need a “current selected item” or “current best item” while only reading data.

fn longest_name<'a>(names: &'a [String]) -> &'a String {
    let mut longest: &String = &names[0];

    for name in &names[1..] {
        if name.len() > longest.len() {
            longest = name;
        }
    }

    longest
}

The function never changes the names. It only changes which name longest points to.

Small Comparison

let mut age = 30;                    // mut T
age += 1;

let name = String::from("Ana");
let read_only_name = &name;           // &T

let mut message = String::from("hello");
let editable_message = &mut message;  // &mut T
editable_message.push('!');

let first = String::from("red");
let second = String::from("blue");

let mut selected: &String = &first;   // mut &T
selected = &second;

The practical difference is:

  • mut T: change your own value
  • &T: read someone else’s value
  • &mut T: change someone else’s value with permission
  • mut &T: change which value you are looking at

Mapping to Other Languages

mut T

Rust:

let mut x = 1;
x = 2;

JavaScript:

let x = 1;
x = 2;

Python:

x = 1
x = 2

C:

int x = 1;
x = 2;

This is the simplest case: a normal variable that can change.

&T

Rust:

fn print_value(value: &i32) {
    println!("{value}");
}

C closest equivalent:

const int* value;

In JavaScript and Python, references exist, but the language does not have the same built-in read-only borrowing rule.

&mut T

Rust:

fn increase(value: &mut i32) {
    *value += 1;
}

C closest equivalent:

int* value;

But Rust adds safety rules. It makes sure only one mutable reference exists at a time.

JavaScript and Python allow shared mutation more freely, but they do not protect you from aliasing bugs in the same way.

mut &T

Rust:

let mut selected = &first;
selected = &second;

JavaScript:

let selected = first;
selected = second;

Python:

selected = first
selected = second

C closest equivalent:

const int* selected = &first;
selected = &second;

The variable can point somewhere else, but the value is still read-only through that handle.

TL;DR: Purpose-Driven Cases

Use the syntax based on what you are trying to do.

I have a value and I want to change it

Use mut T.

let mut count = 0;
count += 1;

Good for:

  • counters
  • totals
  • local variables
  • temporary values
  • values you own

I want to pass a value to a function without giving it away

Use &T.

fn print_count(count: &i32) {
    println!("{count}");
}

Good for:

  • printing
  • checking
  • reading
  • validation
  • functions that should not modify data

I want a function to update an existing value

Use &mut T.

fn reset_count(count: &mut i32) {
    *count = 0;
}

Good for:

  • modifying a string
  • updating a list
  • changing a struct
  • resetting state
  • in-place changes

I want to switch between values, but only read them

Use mut &T.

let mut current = &first;
current = &second;

Good for:

  • selected item
  • current item
  • longest item
  • best match
  • cursor-like logic over read-only data

Conclusion

Rust becomes much easier when you separate two ideas:

  1. Can the variable itself change?
  2. Can the value behind the variable change?

The short version is:

  • mut T: I own it, and I want to change it.
  • &T: I only want to read it.
  • &mut T: I want to borrow it and change it.
  • mut &T: I want to change which value I am reading.

Rust is not making mutability complicated for no reason. It is making ownership, borrowing, and mutation visible so the compiler can prevent common bugs.