Generics

Generic Implementations

A generic implementation (impl<T> Type<T>) is an impl block that declares type parameters after the impl keyword so its inherent methods, associated functions, or trait implementations apply across a family of generic instantiations.

Why T Appears Twice in impl<T> Type<T>

In impl<T> Buffer<T>, the two occurrences of <T> serve distinct grammatical roles:

impl<T> Buffer<T> { ... }
    ^^^       ^^^
     |         +-- Uses T as the type argument to the struct Buffer
     +------------ Declares T as a generic type parameter in scope for this block

If you write impl Buffer<T> without declaring <T> after impl, the compiler looks for a concrete type literally named T in the current module and emits error E0412:

// ❌ does not compile
struct Buffer<T> {
    items: Vec<T>,
}

impl Buffer<T> {
    fn len(&self) -> usize {
        self.items.len()
    }
}

fn main() {}
error[E0412]: cannot find type `T` in this scope
 --> src/main.rs:6:13
  |
6 | impl Buffer<T> {
  |     -       ^ not found in this scope
  |     |
  |     help: you might be missing a type parameter: `<T>`

Conditional Implementation Blocks

A single generic struct can have multiple impl blocks with progressively stricter trait bounds. Each block unlocks additional methods only when the concrete type argument satisfies that block's bounds:

use std::fmt::Display;

struct Pair<T> {
    left: T,
    right: T,
}

// Available for ALL types T:
impl<T> Pair<T> {
    fn new(left: T, right: T) -> Self {
        Self { left, right }
    }
}

// Available ONLY when T implements Display + PartialOrd:
impl<T: Display + PartialOrd> Pair<T> {
    fn print_larger(&self) {
        if self.left >= self.right {
            println!("Largest member is left: {}", self.left);
        } else {
            println!("Largest member is right: {}", self.right);
        }
    }
}

struct Opaque;

fn main() {
    let numbers = Pair::new(14, 29);
    numbers.print_larger();

    // Pair<Opaque> can still be constructed via Pair::new, even though it lacks print_larger():
    let _opaque_pair = Pair::new(Opaque, Opaque);
}
Largest member is right: 29

Implementing a Trait for a Generic Type

Generic impl blocks also implement traits conditionally for generic types (impl<T: Bound> Trait for Type<T>):

use std::fmt;

struct Matrix2x2<T> {
    data: [[T; 2]; 2],
}

impl<T: fmt::Display> fmt::Display for Matrix2x2<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "[{} {}]\n[{} {}]",
            self.data[0][0], self.data[0][1], self.data[1][0], self.data[1][1]
        )
    }
}

fn main() {
    let mat = Matrix2x2 {
        data: [[1, 2], [3, 4]],
    };
    println!("{mat}");
}
[1 2]
[3 4]

Preventing Overlapping Inherent Implementations

Rust forbids defining two inherent methods with the same name on overlapping instantiations of a generic type (error E0592). For example, you cannot define fn reset(&mut self) in both impl<T> Boxed<T> and impl Boxed<i32> because Boxed<i32> matches both blocks:

// ❌ does not compile
struct Boxed<T>(T);

impl<T> Boxed<T> {
    fn describe(&self) -> &'static str {
        "generic"
    }
}

impl Boxed<i32> {
    fn describe(&self) -> &'static str {
        "i32 specialization"
    }
}

fn main() {}
error[E0592]: duplicate definitions with name `describe`
  --> src/main.rs:11:5
   |
5  |     fn describe(&self) -> &'static str {
   |     ---------------------------------- other definition for `describe`
...
11 |     fn describe(&self) -> &'static str {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `describe`