---
title: "15.4 Generic methods"
description: "Implementing methods on generic types with impl<T> blocks, and writing methods that exist only for a specific instantiation like Point<f64>."
url: "https://learnrust.net/chapter-15/generic-methods/"
last_updated: "2026-06-13"
---

# 15.4 Generic methods

A generic struct holds data of type `T`; to give it behavior, you write methods in an `impl` block, just like chapter 10. The only new wrinkle is that the `impl` itself has to be generic, and once you see why, a useful trick falls out: you can write methods that exist *only* for certain concrete types.

## impl blocks on generic types

To add methods to `Point<T>`, the `impl` block must declare the type parameter too:

```rust
struct Point<T> {
    x: T,
    y: T,
}

impl<T> Point<T> {
    fn x(&self) -> &T {
        &self.x
    }
}

fn main() {
    let p = Point { x: 5, y: 10 };
    println!("{}", p.x());
}
```

```
5
```

Read the line carefully: `impl<T> Point<T>`. The first `<T>` declares a type parameter for the `impl` block, and `Point<T>` says "for `Point` of that type." You need both because the `impl` is itself generic; it provides this method for `Point<T>` *whatever* `T` is. The method `x` returns `&T`, a reference to the field, and works for `Point<i32>`, `Point<String>`, any `Point`. This is the lesson [10.5](https://learnrust.net/chapter-10/methods-and-impl-blocks/) method syntax, with `<T>` threaded through so the compiler knows the `T` in the method body is the same `T` as the struct's.

Inside such a method, `T` is still opaque: you can move it, return references to it, store it, but you can't compare or print it without a bound (the same rule as generic functions, lesson [15.2](https://learnrust.net/chapter-15/generic-functions/)). `Point::x` only hands back a reference, so no bound is needed.

## Methods for a specific type only

Here's the trick. An `impl` block doesn't have to be generic. You can write `impl Point<f64>` (a concrete type, no `<T>`), and the methods inside it exist *only* for `Point<f64>`, not for `Point<i32>` or any other instantiation:

```rust
impl Point<f64> {
    fn distance_from_origin(&self) -> f64 {
        (self.x * self.x + self.y * self.y).sqrt()
    }
}

fn main() {
    let float_point = Point { x: 3.0, y: 4.0 };
    println!("{}", float_point.distance_from_origin());

    let int_point = Point { x: 3, y: 4 };
    // int_point.distance_from_origin(); // refused: only Point<f64> has it
}
```

```
5
```

`distance_from_origin` calls `.sqrt()`, which exists for `f64` but not `i32`, so it only makes sense for `Point<f64>`. By writing `impl Point<f64>` instead of `impl<T> Point<T>`, you give the method to *just* that type. Call it on a `Point<i32>` and the compiler says the method doesn't exist, because for `Point<i32>` it genuinely doesn't. This lets a generic type offer extra capabilities for the specific types that can support them, without forcing every instantiation to have them.

> **Key insight**
>
> `impl<T> Point<T>` adds a method to *every* `Point`; `impl Point<f64>` adds a method to *only* `Point<f64>`. The first is for behavior that works regardless of `T`; the second is for behavior that needs a specific type's capabilities (like `f64`'s `sqrt`). You'll see both in the standard library: most of `Vec`'s methods are generic over its element type, but some exist only when the elements meet certain conditions, the more general version of this same idea (which chapter 16's trait bounds make fully expressive).

## Methods can have their own generics

A method can also introduce type parameters of its own, separate from the struct's. This is rarer but worth recognizing: the method's `<U>` is independent of the struct's `<T>`.

```rust
impl<T> Point<T> {
    fn pair_with<U>(self, other: U) -> (T, U) {
        (self.x, other)
    }
}
```

`pair_with` is generic over `U`, a type chosen fresh at the call, distinct from the `Point`'s `T`. It takes `self` by value (consuming the point, lesson [10.5](https://learnrust.net/chapter-10/methods-and-impl-blocks/)) and returns a tuple of the point's `x` and the other value. You won't write these often, but they explain method signatures like `Option::map` that carry their own type parameters beyond the type they're defined on.

## Quiz time

**Question #1**

Why does an `impl` block on a generic struct need to be written `impl<T> Point<T>` rather than just `impl Point`?

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

Because `Point` by itself isn't a complete type; it's `Point<T>` for some `T`. The leading `impl<T>` declares the type parameter so the block can talk about `Point<T>` generically and so the `T` used in the method bodies refers to the struct's type parameter. `impl Point` alone wouldn't name the parameter.

</details>

**Question #2**

What's the difference between `impl<T> Point<T>` and `impl Point<f64>`?

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

`impl<T> Point<T>` defines methods available on *every* `Point`, whatever its type. `impl Point<f64>` defines methods available *only* on `Point<f64>`. The concrete-type `impl` is how you give a method to one instantiation that needs that type's specific capabilities (like `f64::sqrt`), without requiring all instantiations to support it.

</details>

**Question #3**

You have a `Wrapper<T>` and want a `describe` method on *all* wrappers plus a `sqrt` method only on `Wrapper<f64>`. Sketch the two `impl` headers.

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

```rust
impl<T> Wrapper<T> {
    fn describe(&self) -> &str { "a wrapper" }
}

impl Wrapper<f64> {
    fn sqrt(&self) -> f64 { self.value.sqrt() }
}
```

The first (`impl<T>`) gives `describe` to every `Wrapper`; the second (`impl Wrapper<f64>`) gives `sqrt` only to the `f64` instantiation, where `.sqrt()` is available.

</details>

You can now write generic types and methods. There's one question left that's bothered careful readers since lesson [15.1](https://learnrust.net/chapter-15/the-problem-generics-solve/): if one generic function serves many types, what does the compiled program actually contain? The next lesson answers it, and explains why Rust's generics are "zero-cost."

## Sitemap

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