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`