Question

Rust mut Before a Variable Name vs After the Colon Explained

rustvariablessyntaxreferencemutable

Question

In Rust, I saw these two function signatures:

fn modify_foo(mut foo: Box<i32>) {
    *foo += 1;
    *foo;
}

fn modify_foo(foo: &mut i32) {
    *foo += 1;
    *foo;
}

Why is mut placed differently in these examples?

I expected the first function might also be written like this:

fn modify_foo(foo: mut Box<i32>) {
    /* ... */
}

What is the difference between putting mut before the parameter name and using &mut in the type?

Short Answer

By the end of this page, you will understand that Rust uses mut in two different roles:

  • mut foo: T makes the binding mutable, meaning the local variable foo can be reassigned or used in ways that require a mutable binding.
  • foo: &mut T means the type is a mutable reference, so the function receives permission to mutate the value being borrowed.

These look similar, but they solve different problems. One changes how the local name behaves, and the other changes what kind of value is being passed in.

Concept

Rust separates two ideas that many beginners initially combine:

  1. Is the variable binding mutable?
  2. Is the value being accessed through a mutable reference?

These are not the same thing.

1. mut foo: T means a mutable binding

When mut appears before a parameter or variable name, it applies to the binding.

fn example(mut x: i32) {
    x += 1;
}

Here, x is a local variable inside the function. Marking it mut means:

  • you can reassign x
  • you can call operations that require mutable access to the binding

This does not mean the caller's original value becomes mutable. Parameters are passed into the function, and mut only affects the local binding inside that function.

2. foo: &mut T means a mutable reference type

When mut appears as part of &mut T, it is part of the type.

fn example(x: &mut i32) {
    *x += 1;
}

This means:

  • x is a reference
  • that reference gives mutable access to an i32
  • the function can change the caller's original value through that reference

So &mut is about borrowing with write access, not about whether the local variable name can be reassigned.

Why the two example signatures differ

Example 1

fn modify_foo(mut foo: Box<i32>) {
    *foo += 1;
}

foo is a Box<i32>, which means the function owns the box. The mut before foo makes the local binding mutable.

Because foo is a mutable binding, Rust allows mutable dereferencing:

*foo += 1;

The function is changing the value inside the owned Box.

Example 2

fn modify_foo(foo: &mut i32) {
    *foo += 1;
}

Here, foo is not an owned box. It is a mutable reference to an i32. The function does not own the value, but it is allowed to mutate it through the reference.

In this case, mut belongs to the type because the important fact is that the reference itself is mutable access.

Why foo: mut Box<i32> is invalid

Rust syntax does not allow mut in that position for ordinary types.

fn modify_foo(foo: mut Box<i32>) {
    // invalid syntax
}

That would suggest mut is part of the type, but Box<i32> is not a special mutable type. Rust does not have a separate type called mut Box<i32>.

Instead:

  • mut foo: Box<i32> changes the binding
  • foo: &mut i32 changes the type

Why this matters

This distinction is central to Rust:

  • mutability of a binding controls what you can do with the local variable name
  • mutability of a reference controls whether you can modify the borrowed data

Understanding this helps with ownership, borrowing, function parameters, and compiler errors about mutability.

Mental Model

Think of Rust mutability as two separate labels:

Label 1: Can I move or change this handle?

This is the binding:

mut foo: T

Imagine foo is a labeled handle in your hand. If the handle is mutable, you can change how you use that handle, such as reassigning it.

Label 2: Does this handle let me edit the thing it points to?

This is the reference type:

foo: &mut T

Now imagine the handle points to a box in a storage room. A normal reference is like a viewing pass. A mutable reference is like an editing pass.

So:

  • mut foo: T = the local handle is changeable
  • foo: &mut T = the handle gives write access to the underlying value

You can even combine them:

fn example(mut x: &mut i32) {
    *x += 1;
}

This means:

  • x is a mutable reference to an i32
  • the local binding x is also mutable

That combination is less common for beginners, but it shows these are separate ideas.

Take Quiz

Syntax and Examples

Core syntax

Mutable binding

fn add_one(mut x: i32) {
    x += 1;
    println!("{x}");
}

x is a local mutable variable inside the function.

Mutable reference type

fn add_one(x: &mut i32) {
    *x += 1;
}

x is a mutable reference, so the function can modify the original value.

Owned value with mutable binding

fn update_box(mut b: Box<i32>) {
    *b += 1;
    println!("{}", *b);
}

b is owned by the function. Since the binding is mutable, the value inside the box can be changed through mutable dereferencing.

Borrowed value with mutable reference

fn update_ref(x: &mut i32) {
    *x += 1;
}

fn main() {
    let mut value = 10;
    update_ref(&mut value);
    println!("{value}"); // 11
}

Here the function borrows value and changes it in place.

Combining both forms

fn example(mut x: &mut i32) {
    *x += 1;
}

This is valid, but the mut before x only makes the local binding mutable. It is not required just to write through x.

A helpful contrast

fn owned(mut x: String) {
    x.push('!');
    println!("{x}");
}

fn borrowed(x: &mut String) {
    x.push('!');
}
  • owned receives ownership of the String
  • borrowed receives temporary mutable access to the caller's String

Both can modify string contents, but for different reasons.

Step by Step Execution

Consider this example:

fn add_to_box(mut b: Box<i32>) {
    *b += 1;
    println!("inside function: {}", *b);
}

fn add_to_ref(x: &mut i32) {
    *x += 1;
    println!("inside function: {}", *x);
}

fn main() {
    let boxed = Box::new(5);
    add_to_box(boxed);

    let mut value = 5;
    add_to_ref(&mut value);
    println!("after function: {}", value);
}

What happens in add_to_box

1. boxed is created

let boxed = Box::new(5);

A box owning the value 5 is created.

2. Ownership moves into the function

add_to_box(boxed);

The function now owns the Box<i32>.

3. The parameter binding is mutable

fn add_to_box(mut b: Box<i32>)

This lets the function use b mutably.

4. The boxed value is updated

*b += 1;

The value inside the box changes from 5 to 6.

5. The box is dropped at the end of the function

Because ownership was moved in, the original boxed in main is no longer usable.

What happens in add_to_ref

1. A mutable local variable is created

let mut value = 5;

2. A mutable reference is passed

add_to_ref(&mut value);

The function borrows value with write access.

3. The function changes the original value

*x += 1;

The referenced i32 changes from 5 to 6.

4. Control returns to main

The borrow ends, and value is still available.

println!("after function: {}", value);

This prints 6.

Key takeaway

  • mut b: Box<i32>: mutable owned binding inside the function
  • x: &mut i32: mutable borrowed access to someone else's data

Real World Use Cases

When mut variable: T is used

This is common when a function takes ownership of a value and modifies it before returning or consuming it.

Examples

  • Updating an owned String before returning it
  • Modifying a Vec<T> passed by value
  • Working with Box<T> or custom structs the function owns
  • Reassigning a parameter during processing
fn normalize(mut name: String) -> String {
    name.make_ascii_lowercase();
    name
}

When value: &mut T is used

This is common when a function should modify existing data without taking ownership.

Examples

  • Updating a counter
  • Appending to a shared buffer
  • Mutating a struct passed from caller code
  • In-place parsing, formatting, or transformation
fn increment(counter: &mut i32) {
    *counter += 1;
}

In applications

  • Web servers mutate request state or response builders through &mut
  • CLI tools update buffers and configuration structs in place
  • Game loops update positions, health, and world state through mutable references
  • Data processing code may take ownership for transformations or borrow mutably for in-place edits
Take Quiz

Real Codebase Usage

In real Rust projects, developers choose between mutable bindings and mutable references based on ownership design.

Common pattern: mutate owned input, then return it

fn add_suffix(mut s: String) -> String {
    s.push_str("_done");
    s
}

This is useful in pipelines where ownership is being transferred anyway.

Common pattern: in-place mutation via &mut

fn reset_flag(flag: &mut bool) {
    *flag = false;
}

This avoids moving ownership and makes the function's intent explicit.

Common pattern: mutating struct fields

struct Config {
    debug: bool,
}

fn enable_debug(config: &mut Config) {
    config.debug = true;
}

Guarding APIs with borrowing rules

A function that takes &mut T clearly says:

  • I will not own this value
  • I may change it
  • you cannot use another conflicting borrow at the same time

That makes APIs safer and easier to reason about.

When mut on the binding is needed inside a function

Sometimes the binding itself must be reassigned:

fn process(mut text: String) -> String {
    if text.is_empty() {
        text = String::from("default");
    }
    text
}

Practical guideline

  • Use mut name: T when the function owns the value and needs a mutable local binding
  • Use name: &mut T when the caller should keep ownership but allow mutation

Common Mistakes

Mistake 1: Thinking mut always means the same thing

Many beginners assume all mut keywords do the same job.

fn a(mut x: i32) {}
fn b(x: &mut i32) {}

These are different:

  • mut x changes the binding
  • &mut i32 changes the reference type

Mistake 2: Trying to write foo: mut T

This is invalid for normal parameter types.

fn broken(x: mut String) {}

Use this instead:

fn fixed(mut x: String) {}

Mistake 3: Forgetting that &mut changes the caller's value

fn set_zero(x: &mut i32) {
    *x = 0;
}

This modifies the original value, not a copy.

Mistake 4: Forgetting to make the original variable mutable

Broken code:

fn add_one(x: &mut i32) {
    *x += 1;
}

fn main() {
    let value = 5;
    add_one(&mut value);
}

This fails because value itself is not declared mutable.

Fixed code:

fn add_one(x: &mut i32) {
    *x += 1;
}

fn main() {
    let mut value = 5;
    add_one(&mut value);
}

Mistake 5: Assuming mut is needed on a mutable reference binding

This is valid:

fn add_one(x: &mut i32) {
    *x += 1;
}

You do not need this just to mutate through the reference:

fn add_one(mut x: &mut i32) {
    *x += 1;
}

The extra mut only matters if you want to reassign the local variable x itself.

Mistake 6: Confusing ownership with borrowing

fn consume(mut s: String) {
    s.push('!');
}

This takes ownership.

fn borrow(s: &mut String) {
    s.push('!');
}

This borrows mutably.

Choose based on whether the caller should keep using the original value.

Comparisons

SyntaxWhat mut applies toOwns the value?Can modify caller's original value?Common use
mut x: TThe local bindingYes, if T is passed by valueNo, not directlyMutating or reassigning an owned parameter
x: &mut TThe reference typeNoYesIn-place mutation through borrowing
x: &TImmutable reference typeNoNoRead-only borrowing
let mut x = value;Local bindingYes or borrowed, depending on valueDepends on typeMutable local variable

mut x: T vs x: &mut T

fn owned(mut s: String) {
    s.push('!');
}

fn borrowed(s: &mut String) {
    s.push('!');
}
Featuremut s: Strings: &mut String
OwnershipFunction takes ownershipCaller keeps ownership
Mutation targetThe owned value inside the functionThe caller's original value
Reassignment of parameterYes, if binding is mutOnly if binding itself is mut
Need caller to pass &mutNoYes

&T vs &mut T

TypeCan read?Can write?Borrow kind
&TYesNoShared borrow
&mut TYesYesExclusive mutable borrow
Take Quiz

Cheat Sheet

Quick rules

  • mut name: T = mutable binding
  • name: &mut T = mutable reference type
  • name: mut T = invalid syntax for ordinary types

Common patterns

fn a(mut x: i32) {
    x += 1;
}

fn b(x: &mut i32) {
    *x += 1;
}

fn c(mut s: String) -> String {
    s.push('!');
    s
}

fn d(s: &mut String) {
    s.push('!');
}

What each means

  • mut x means the local variable x can change
  • &mut T means the function can mutate the referenced T
  • These can be combined if needed
fn e(mut x: &mut i32) {
    *x += 1;
}

Remember

  • Binding mutability and reference mutability are separate concepts
  • &mut affects the type
  • mut before the name affects the binding
  • Use &mut when you want to modify the caller's value without taking ownership

FAQ

Why is mut foo: T different from foo: &mut T in Rust?

mut foo: T makes the local parameter binding mutable. foo: &mut T means the function receives a mutable reference and can modify the borrowed value.

Can I write foo: mut Box<i32> in Rust?

No. That is not valid Rust syntax. For a mutable binding, write mut foo: Box<i32>.

Does mut foo: T let a function change the caller's original value?

Not by itself. It only makes the local owned binding mutable inside the function.

Why can *foo += 1 work with mut foo: Box<i32>?

Because the function owns the Box<i32>, and the binding is mutable, so Rust allows mutable access to the boxed value.

Do I need mut before a parameter name if the type is &mut T?

Usually no. &mut T already allows mutation of the referenced value. Add mut before the name only if you need to reassign the local parameter variable itself.

What is the difference between &T and &mut T?

&T is an immutable borrow for reading. &mut T is a mutable borrow for writing and requires exclusive access.

When should I choose T versus &mut T as a parameter?

Use T when the function should take ownership. Use &mut T when the caller should keep ownership but allow in-place mutation.

Take Quiz

Mini Project

Description

Build a small Rust program that demonstrates the difference between modifying an owned value and modifying a borrowed value. This project helps you see when mut affects only a local binding and when &mut affects the caller's data.

Goal

Create a program with one function that takes ownership of a String and another that mutably borrows a String, then observe how each function changes data.

Requirements

  • Create one function that accepts mut text: String and modifies it.
  • Create another function that accepts text: &mut String and modifies it.
  • In main, call both functions and print the results.
  • Show that the owned value is moved, while the borrowed value remains usable after the function call.
Take Quiz

Keep learning

Related questions

View more