Menu
Coddy logo textTech

Mutable Methods

Part of the Object Oriented Programming section of Coddy's Rust journey — lesson 3 of 61.

Sometimes methods need to do more than just read data—they need to change it. To create methods that can modify a struct's fields, we use &mut self instead of &self.

The mut keyword indicates a mutable borrow, giving the method permission to alter the instance's internal state:

struct Counter {
    value: i32,
}

impl Counter {
    fn increment(&mut self) {
        self.value += 1;
    }
    
    fn decrement(&mut self) {
        self.value -= 1;
    }
    
    fn get(&self) -> i32 {
        self.value
    }
}

Notice that increment and decrement use &mut self because they modify value, while get uses &self since it only reads the data.

When calling mutable methods, the instance itself must be declared as mutable:

fn main() {
    let mut counter = Counter { value: 0 };
    
    counter.increment();
    counter.increment();
    println!("{}", counter.get()); // 2
    
    counter.decrement();
    println!("{}", counter.get()); // 1
}

If you forget the mut keyword when creating the instance, Rust will prevent you from calling any &mut self methods on it. This ensures you're always aware when your data might change.

challenge icon

Challenge

Easy

Create a BankAccount struct with a single field: balance (i32).

Add an implementation block for BankAccount with three methods:

  • deposit — takes &mut self and an amount: i32, adds the amount to the balance
  • withdraw — takes &mut self and an amount: i32, subtracts the amount from the balance
  • get_balance — takes &self and returns the current balance as i32

You will receive three inputs:

  • First line: the initial balance (i32)
  • Second line: the deposit amount (i32)
  • Third line: the withdrawal amount (i32)

Create a mutable BankAccount instance with the initial balance, then deposit the given amount, withdraw the given amount, and print the final balance.

Expected output format:

{final_balance}

Cheat sheet

Methods that modify struct fields use &mut self (mutable borrow), while methods that only read data use &self:

struct Counter {
    value: i32,
}

impl Counter {
    fn increment(&mut self) {
        self.value += 1;
    }
    
    fn decrement(&mut self) {
        self.value -= 1;
    }
    
    fn get(&self) -> i32 {
        self.value
    }
}

To call mutable methods, the instance must be declared as mutable with let mut:

let mut counter = Counter { value: 0 };

counter.increment();
counter.increment();
println!("{}", counter.get()); // 2

counter.decrement();
println!("{}", counter.get()); // 1

Without the mut keyword on the instance, Rust will prevent calling any &mut self methods.

Try it yourself

use std::io;

// TODO: Define the BankAccount struct here


// TODO: Add the implementation block for BankAccount with deposit, withdraw, and get_balance methods


fn main() {
    let mut input = String::new();
    
    // Read initial balance
    io::stdin().read_line(&mut input).expect("Failed to read line");
    let initial_balance: i32 = input.trim().parse().expect("Invalid number");
    
    input.clear();
    
    // Read deposit amount
    io::stdin().read_line(&mut input).expect("Failed to read line");
    let deposit_amount: i32 = input.trim().parse().expect("Invalid number");
    
    input.clear();
    
    // Read withdrawal amount
    io::stdin().read_line(&mut input).expect("Failed to read line");
    let withdraw_amount: i32 = input.trim().parse().expect("Invalid number");
    
    // TODO: Create a mutable BankAccount instance with initial_balance
    // TODO: Call deposit with deposit_amount
    // TODO: Call withdraw with withdraw_amount
    // TODO: Print the final balance using get_balance
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming