Generics

#[derive(Debug)]
struct Point<T> {
    x: T,
    y: T,
}

#[derive(Debug)]
struct Point2D<A, B> {
    x: A,
    y: B,
}

Generics in method definition

T declared just after impl will let Rust compiler identifies that the type paramater in the angle brackets in Point is a generic type rather than a concrete.

impl<T> Point<T> {
    fn new(x: T, y: T) -> Point<T> {
        Point { x, y }
    }
}

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

impl<A, B> Point2D<A, B> {
    fn new(x: A, y: B) -> Self {
        Self { x, y }
    }

    fn x(&self) -> &A {
        &self.x
    }

    fn y(&self) -> &B {
        &self.y
    }
}

Generic type paramaters in a struct definition can be different from the ones used in that struct's method signatures.

impl<X1, Y1> Point2D<X1, Y1> {
    fn mixup<X2, Y2>(self, other: Point2D<X2, Y2>) -> Point2D<X1, Y2> {
        Point2D {
            x: self.x,
            y: other.y,
        }
    }
}

An impl block can only apply to a struct with a particular concrete type for the generic type paramater.

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

Runnable Code

#[derive(Debug)]
struct Point<T> {
    x: T,
    y: T,
}

#[derive(Debug)]
struct Point2D<A, B> {
    x: A,
    y: B,
}

impl<T> Point<T> {
    fn new(x: T, y: T) -> Point<T> {
        Point { x, y }
    }
}

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

impl<A, B> Point2D<A, B> {
    fn new(x: A, y: B) -> Self {
        Self { x, y }
    }

    fn x(&self) -> &A {
        &self.x
    }

    fn y(&self) -> &B {
        &self.y
    }
}

impl<X1, Y1> Point2D<X1, Y1> {
    fn mixup<X2, Y2>(self, other: Point2D<X2, Y2>) -> Point2D<X1, Y2> {
        Point2D {
            x: self.x,
            y: other.y,
        }
    }
}

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

fn main() {
    let p = Point::new(10.10, 20.20);
    println!("{:?}", p);
    println!("{:?}", p.x());
    println!("{:?}", p.distance());

    let p_2d = Point2D::new(1, 2.2);
    println!("{:?}", p_2d);
    println!("x = {:?}", p_2d.x());
    println!("y = {:?}", p_2d.y());

    let mixed_point = p_2d.mixup(Point2D::new(1000.0, 2000.0));
    print!("{:?}", mixed_point);
}