Generic Methods
A generic method is a method attached to a struct, enum, or trait that operates on generic type parameters—either the type parameters declared on the enclosing impl<T> block, additional type parameters declared on the fn signature itself, or both.
Methods Using the Type's Generic Parameter
To define methods on a generic type Point<T> that work for any T, declare T right after impl (impl<T> Point<T>). That declaration tells the compiler that the T in Point<T> is a generic type parameter rather than a concrete type named T:
struct Point<T> {
x: T,
y: T,
}
impl<T> Point<T> {
fn x(&self) -> &T {
&self.x
}
fn into_tuple(self) -> (T, T) {
(self.x, self.y)
}
}
fn main() {
let p = Point { x: 12, y: 34 };
println!("p.x() = {}", p.x());
let (x, y) = p.into_tuple();
println!("tuple = ({x}, {y})");
}
p.x() = 12
tuple = (12, 34)
Methods Restricted to a Specific Concrete Type
An impl block can omit <T> after impl and name a specific concrete instantiation such as impl Point<f64>. Methods inside that block exist only on Point<f64> and are unavailable on Point<i32> or any other instantiation:
struct Point<T> {
x: T,
y: T,
}
impl Point<f64> {
fn distance_from_origin(&self) -> f64 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
fn main() {
let p = Point { x: 3.0_f64, y: 4.0_f64 };
println!("Distance: {}", p.distance_from_origin());
}
Distance: 5
Calling distance_from_origin() on a Point<i32> produces a compile-time error (E0599) because no such method exists for Point<{integer}>:
// ❌ does not compile
struct Point<T> {
x: T,
y: T,
}
impl Point<f64> {
fn distance_from_origin(&self) -> f64 {
(self.x.powi(2) + self.y.powi(2)).sqrt()
}
}
fn main() {
let int_point = Point { x: 3, y: 4 };
println!("{}", int_point.distance_from_origin());
}
error[E0599]: no method named `distance_from_origin` found for struct `Point<{integer}>` in the current scope
--> src/main.rs:15:30
|
2 | struct Point<T> {
| --------------- method `distance_from_origin` not found for this struct
...
15 | println!("{}", int_point.distance_from_origin());
| ^^^^^^^^^^^^^^^^^^^^ method not found in `Point<{integer}>`
|
= note: the method was found for
- `Point<f64>`
Methods Introducing Their Own Type Parameters
A method inside impl<T> Point<T> can declare additional type parameters on its own fn signature (such as fn mixup<U>(...)) that are independent of T:
#[derive(Debug)]
struct Point<X1, Y1> {
x: X1,
y: Y1,
}
impl<X1, Y1> Point<X1, Y1> {
fn mixup<X2, Y2>(self, other: Point<X2, Y2>) -> Point<X1, Y2> {
Point {
x: self.x,
y: other.y,
}
}
}
fn main() {
let p1 = Point { x: 5, y: 10.4 };
let p2 = Point { x: "Hello", y: 'c' };
let p3 = p1.mixup(p2);
println!("p3 = ({}, {})", p3.x, p3.y);
}
p3 = (5, c)
Here X1 and Y1 belong to the receiver's impl<X1, Y1> block, while X2 and Y2 are scoped strictly to the mixup method and inferred from the other argument.
| Type Parameter Placement | Scope | When Bound |
|---|---|---|
impl<T> Type<T> |
All methods inside the impl block |
When the Type<T> instance is constructed |
fn method<U>(&self, arg: U) |
Only that single method | Each time method is called on an instance |