---
title: "10.5 Methods and impl blocks"
description: "How impl blocks attach methods to a struct, the difference between &self, &mut self, and self, and why method receivers are just chapters 8 and 9 in new clothing."
url: "https://learnrust.net/chapter-10/methods-and-impl-blocks/"
last_updated: "2026-06-13"
---

# 10.5 Methods and impl blocks

You've called methods since chapter 1. `text.len()`, `name.trim()`, `guess.cmp(&secret)`, `numbers.push(3)`: all of those are methods, functions that belong to a type and are called with a dot. This lesson shows you how to write your own, and you'll find that the only genuinely new thing is the syntax. The hard part, who owns the value and who's borrowing it, you finished in chapter 9.

## A method is a function with a home

Start with a plain function that takes a `Rectangle` and returns its area:

```rust
struct Rectangle {
    width: f64,
    height: f64,
}

fn area(rect: &Rectangle) -> f64 {
    rect.width * rect.height
}

fn main() {
    let r = Rectangle { width: 4.0, height: 2.5 };
    println!("{}", area(&r));
}
```

```
10
```

This works, but `area` is a loose function that happens to be about rectangles. Nothing ties it to `Rectangle`, and in a big program it floats off among unrelated functions. A **method** is the same function, attached to the type, so it lives with the data it operates on. You write methods inside an **`impl` block** (short for *implementation*):

```rust
impl Rectangle {
    fn area(&self) -> f64 {
        self.width * self.height
    }
}

fn main() {
    let r = Rectangle { width: 4.0, height: 2.5 };
    println!("{}", r.area());
}
```

```
10
```

Three things changed. The function moved inside `impl Rectangle { ... }`, which says "the following functions belong to `Rectangle`." The parameter `rect: &Rectangle` became `&self`, a special first parameter naming the instance the method is called on. And the call site went from `area(&r)` to `r.area()`: the receiver moves in front of the dot. `r.area()` is almost literally `Rectangle::area(&r)`, and you can write it that way, but nobody does.

The `impl` block sits separate from the `struct` definition. The struct says what data a `Rectangle` holds; the `impl` says what a `Rectangle` can *do*. You can even have several `impl` blocks for one type; the compiler merges them.

## The three forms of self

That `&self` parameter is the whole game, and it's the borrowing chapter you already passed. `&self` is shorthand for `self: &Self`, where `Self` is "the type this `impl` is for." A method's first parameter can take the receiver in exactly the three ways lesson [9.4](https://learnrust.net/chapter-9/references-and-functions/) taught for any value:

**`&self`** borrows the instance immutably. The method can read fields but not change them, and the caller keeps full ownership. This is the most common form by far, the method equivalent of taking `&Rectangle`:

```rust
impl Rectangle {
    fn area(&self) -> f64 {
        self.width * self.height       // reads, doesn't change
    }
}
```

**`&mut self`** borrows mutably. The method can change fields, and the caller must hold the instance in a `mut` binding. This is `&mut Rectangle`:

```rust
impl Rectangle {
    fn scale(&mut self, factor: f64) {
        self.width *= factor;
        self.height *= factor;
    }
}

fn main() {
    let mut r = Rectangle { width: 4.0, height: 2.5 };
    r.scale(2.0);
    println!("{} x {}", r.width, r.height);
}
```

```
8 x 5
```

**`self`** (no `&`) *takes ownership* of the instance, consuming it. The caller can't use it afterward; this is the method form of passing a value by value, from lesson [8.6](https://learnrust.net/chapter-8/ownership-and-functions/). It's rarer, used when a method transforms a value into something else and the original shouldn't live on:

```rust
impl Rectangle {
    fn into_square(self) -> Rectangle {
        let side = self.width.min(self.height);
        Rectangle { width: side, height: side }
    }
}
```

After `let sq = r.into_square();`, `r` is gone, moved into the method. Methods that consume `self` conventionally start with `into_`, a naming hint you'll see all over the standard library.

> **Key insight**
>
> Choosing between `&self`, `&mut self`, and `self` is the lesson [9.4](https://learnrust.net/chapter-9/references-and-functions/) parameter decision, asked once more: does the method only *read* (`&self`), does it *modify in place* (`&mut self`), or does it *consume and transform* (`self`)? You already know how to answer. The method just writes the receiver before the dot instead of inside the parentheses.

## Why methods read so well

The payoff is at the call site. Compare:

```rust
scale(&mut r, 2.0);     // free function: which argument is the rectangle?
r.scale(2.0);           // method: r is obviously the thing being scaled
```

The method form puts the subject first and the verb second, the way English does. `r.scale(2.0).area()` reads left to right as a chain of actions on `r`, and that chaining is why method syntax dominates real Rust. Methods also group discoverably: type `r.` in an editor with rust-analyzer (lesson [0.7](https://learnrust.net/chapter-0/setting-up-a-code-editor/)) and it lists everything a `Rectangle` can do. Loose functions don't offer that.

> **Best practice**
>
> Default to `&self`. Reach for `&mut self` only when the method genuinely changes the instance, and for `self` only when it consumes it. A method that takes more than it needs (say `&mut self` for something that only reads) forces callers into a `mut` binding for no reason, the same over-borrowing lesson [9.4](https://learnrust.net/chapter-9/references-and-functions/) warned about.

## Methods take other parameters too

`self` is just the first parameter. After it, methods take arguments like any function:

```rust
impl Rectangle {
    fn can_hold(&self, other: &Rectangle) -> bool {
        self.width >= other.width && self.height >= other.height
    }
}

fn main() {
    let big = Rectangle { width: 8.0, height: 6.0 };
    let small = Rectangle { width: 4.0, height: 2.0 };
    println!("{}", big.can_hold(&small));
}
```

```
true
```

`can_hold` borrows `self` immutably (it only compares) and borrows `other` immutably too, so neither rectangle is disturbed. The signature alone tells the caller that `big.can_hold(&small)` reads both and changes neither, which is exactly the contract lesson [9.1](https://learnrust.net/chapter-9/references-borrowing-a-value/) praised.

## Quiz time

**Question #1**

Add a method `perimeter(&self) -> f64` to `Rectangle` and call it on a 3-by-5 rectangle.

<details class="solution">
<summary>Show solution</summary>

```rust
impl Rectangle {
    fn perimeter(&self) -> f64 {
        2.0 * (self.width + self.height)
    }
}

fn main() {
    let r = Rectangle { width: 3.0, height: 5.0 };
    println!("{}", r.perimeter());
}
```

Prints `16`. It only reads the fields, so `&self` is correct.

</details>

**Question #2**

For each method, say which receiver (`&self`, `&mut self`, or `self`) it should take:

a) returns whether the rectangle is a square
b) doubles both dimensions
c) consumes the rectangle and returns its area as an `f64`, discarding the shape

<details class="solution">
<summary>Show solution</summary>

a) `&self`: only reads. b) `&mut self`: changes fields in place; caller needs a `mut` binding. c) `self`: it consumes the rectangle (the shape is thrown away), so taking ownership is appropriate; conventionally you might name it `into_area`.

</details>

**Question #3**

This is refused. Why, and what's the fix?

```rust
impl Rectangle {
    fn grow(&self, extra: f64) {
        self.width += extra;
    }
}
```

<details class="solution">
<summary>Show solution</summary>

`grow` modifies `self.width` but takes `&self`, an immutable borrow, so the assignment is rejected (E0594, the same "cannot assign, behind a `&` reference" family as lesson [9.1](https://learnrust.net/chapter-9/references-borrowing-a-value/)'s E0596). Change the receiver to `&mut self`. The method's job (changing the instance) decides the receiver.

</details>

Methods need an instance to call them on. The next lesson covers functions that belong to the type but *don't* take `self`, including `::new`, which is how Rust builds instances without a special constructor language feature.

## Sitemap

See the full [sitemap](https://learnrust.net/sitemap.md) for all pages.
