Course contentsShow
← Rust
Lesson 214 of 1,9103. Borrowing and ReferencesFree lesson

Applying Mutability to Function Arguments

Write functions that modify input data in place without requiring ownership.

In this lesson, you will learn how to modify data directly within a function by passing a mutable reference instead of taking ownership of the value.

Why Change Data In-Place?

Up until now, you have mostly used immutable references, which allow you to "read" data without owning it. However, if you want a function to update an existing variable, you don't necessarily want to move ownership into that function. Moving ownership would destroy the original variable in the calling scope. Instead, you can pass a mutable reference (&mut T), which grants the function temporary permission to change the value while keeping it alive in the original scope.

Syntax and Usage

To pass a mutable reference, you add mut to both the variable declaration and the function signature. Here is how it looks in practice:

fn increment_score(score: &mut i32) {
    *score += 1;
}

fn main() {
    let mut game_score = 10;
    
    // We pass the address of the variable using &mut
    increment_score(&mut game_score);
    
    println!("New score: {}", game_score); // Prints 11
}

How it works

  1. The Caller: You must declare the original variable as mut so it can be changed. When calling the function, use &mut variable_name.
  2. The Function: The parameter type is &mut T. Inside the function, Rust requires the dereference operator (*) to access the actual value behind the reference so you can perform arithmetic or updates.
  3. The Borrow Checker: Rust strictly enforces that you can only have one mutable reference to a piece of data at a time. This prevents "data races" where two parts of your code try to change the same value simultaneously. Because the function holds a mutable reference, the main function is temporarily blocked from accessing or modifying that variable until the function returns.

By using mutable references, you keep your data where it belongs while giving specific functions the "tools" they need to perform updates, keeping your memory usage efficient and your logic clear.

Key Takeaway: Use &mut T in function arguments when you need to modify data without taking ownership, ensuring you maintain the original variable's scope while gaining temporary write access.