Rust Methods and impl Explained: &self, &mut self, Associated Functions
November 10, 2026
Welcome to episode 11 of Rust for Beginners, a series for complete beginners (no programming experience needed). In the last video, we built our own types with structs. Today, we'll give them behaviour, with methods and impl. Every code block below is the exact code from the video, ready to copy.
- All episodes are in the Rust Tutorial for Beginners playlist.
- Versions used: Rust 1.99.1 on Ubuntu, VS Code with rust-analyzer.
1. New project
Let's create a new project called rectangles, and open it in VS Code.
cargo new rectangles
cd rectangles2. impl
Here's a Rectangle with a width and a height. Methods go inside an impl block, short for implementation.
src/main.rs:
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
}
fn main() {
let rect = Rectangle { width: 30, height: 50 };
println!("Area: {}", rect.area());
}Output: Area: 1500
3. self
A method's first parameter is self: the rectangle it's called on. Ampersand self means it only borrows it, to read.
4. Call
We call a method with a dot: rect dot area.
5. Run A
Let's run it. Thirty times fifty is one thousand five hundred.
cargo run6. More params
Methods can take more parameters after self. can hold checks if another rectangle fits inside this one.
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn can_hold(&self, other: &Rectangle) -> bool {
self.width > other.width && self.height > other.height
}
fn square(size: u32) -> Self {
Self { width: size, height: size }
}
}
fn main() {
let rect = Rectangle { width: 30, height: 50 };
let small = Rectangle::square(10);
println!("Area: {}", rect.area());
println!("Square area: {}", small.area());
println!("Can hold? {}", rect.can_hold(&small));
}Output: Area: 1500 / Square area: 100 / Can hold? true
7. Associated fn
A function in impl without self is an associated function. We call it with two colons, like String colon colon from. square builds a new rectangle with equal sides.
8. Self
Capital Self is just a short name for the type we're implementing: Rectangle.
9. Run B
Let's run it. The square's area is one hundred, and yes, the big rectangle can hold it.
cargo run10. &mut self
To change the struct, a method takes ampersand mut self. scale multiplies both sides.
struct Rectangle {
width: u32,
height: u32,
}
impl Rectangle {
fn area(&self) -> u32 {
self.width * self.height
}
fn scale(&mut self, factor: u32) {
self.width *= factor;
self.height *= factor;
}
}
fn main() {
let rect = Rectangle { width: 30, height: 50 };
rect.scale(2);
println!("Area after scaling: {}", rect.area());
}Error in step 12:
error[E0596]: cannot borrow `rect` as mutable, as it is not declared as mutable
--> src/main.rs:19:5
|
19 | rect.scale(2);
| ^^^^ cannot borrow as mutable
|
help: consider changing this to be mutable
|
18 | let mut rect = Rectangle { width: 30, height: 50 };
| +++Then line 18 becomes let mut rect = .... Output: Area after scaling: 6000
11. Call it
Let's call scale on our rectangle, and run it.
cargo run12. Error
Error: rect is not mutable, so we can't call a method that changes it. Again, the compiler tells us exactly what to do.
13. Fix
Let's add mut, and run again. Sixty times one hundred is six thousand.
cargo runRecap
To recap: methods live in an impl block. Ampersand self reads, ampersand mut self changes. Functions without self are associated functions, called with two colons.