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
EasyCreate a BankAccount struct with a single field: balance (i32).
Add an implementation block for BankAccount with three methods:
deposit— takes&mut selfand anamount: i32, adds the amount to the balancewithdraw— takes&mut selfand anamount: i32, subtracts the amount from the balanceget_balance— takes&selfand returns the current balance asi32
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
}This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Methods and Behavior
Intro Implementation BlocksThe Self ParameterMutable MethodsAssociated FunctionsMultiple Implementation BlocksMethod ChainingRecap - Rectangle Actions4Project: Virtual Pet
Defining the PetFeeding the Pet7Standard Traits
The Debug TraitThe Display TraitClone and CopyEquality TraitsRecap - Printable Point10Project: Document System
The Draw TraitText Component2Encapsulation and Modules
Modules BasicsThe Public KeywordPrivate FieldsGettersSettersRecap - Secure Locker5Generics
Generic StructsGeneric MethodsMultiple Generic TypesGeneric FunctionsRecap - Coordinate Point8Traits as Bounds
Trait Bounds SyntaxMultiple BoundsThe Where ClauseReturning Types with TraitsRecap - Generic Printer11Design Patterns in Rust
Newtype PatternCompositionThe Drop TraitFrom and IntoRecap - Smart Pointer Mock