🎓 A1Learner
🔍

Rust Generic Methods

Generic methods are methods on a generic struct. A method can declare its own type letters, for that one method only.

Struct letters come back after impl

Declare the struct's letters again after the word impl. They belong to the struct.

impl<T, U> Point<T, U> {
    // every method in here works for all T and U
}

A method can bring its own letters

mixup needs two more letters, and they are declared after the method name — they live for that one method only.

fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
    Point { x: self.x, y: other.y }
}

mixup keeps one field from each point

x comes from self, y comes from the other point. This is the closing program's own call:

let p3 = p1.mixup(p2);
println!("p3.x = {}, p3.y = {}", p3.x, p3.y);

An impl for one concrete type only

Write the impl with real types and no letters. Only those values gain the method.

impl Point<f32, f32> {
    fn distance(&self) -> f32 {
        (self.x * self.x + self.y * self.y).sqrt()
    }
}

Only float points can call distance

A concrete-only method may use float-only tools, like sqrt, safely.

let c = Point { x: 3.0, y: 4.0 };
println!("distance = {}", c.distance());

Example

struct Point<T, U> { x: T, y: U }
impl<T, U> Point<T, U> {
    fn mixup<V, W>(self, other: Point<V, W>) -> Point<T, W> {
        Point { x: self.x, y: other.y }
    }
}
impl Point<f32, f32> {
    fn distance(&self) -> f32 { (self.x * self.x + self.y * self.y).sqrt() }
}
fn main() {
    let p1 = Point { x: 5, y: 10.4 };
    let p2 = Point { x: "Hello", y: 'c' };
    let p3 = p1.mixup(p2);
    println!("p3.x = {}, p3.y = {}", p3.x, p3.y);
    let c = Point { x: 3.0, y: 4.0 };
    println!("distance = {}", c.distance());
}

Key points

  • A small concrete impl keeps the general type simple and honest.
  • A method on a generic struct works with the struct's type letters.

In this example, p1 holds an integer and a float, and p2 holds text and a char. mixup keeps p1.x, which is 5, and takes p2.y, which is c, so p3 prints p3.x = 5, p3.y = c. The letters V and W existed only for that call. Below, c is a point of two f32 values. So it alone can use distance. 3 squared plus 4 squared is 25. The square root is 5.

Note

If a method does not fit every T, do not force it into the general impl.

Try it Yourself

Edit the code, then press Run.

Running is simulated · Rust Playground

Exercise

Where are the letters V and W in mixup declared?