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 afterimpl
will let Rust compiler identifies that the type paramater in the angle brackets inPoint
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); }