Simon Shine's Page

$\{\cdot$ Home $\cdot$ Blog $\cdot$ 中文 $\cdot$ GitHub $\cdot$ StackOverflow $\cdot$ $\}$

Implement Rust trait for all types that have another trait

February 15, 2022

Rust traits are powerful. A particularly neat thing you can do is implement a trait for several types at once. To give a simple example, a trait for squaring numbers mainly depends on multiplying them:

trait Square {
    fn square(&self) -> Self;
}

We could implement this trait for a single type like so:

impl Square for u64 {
    fn square(&self) -> Self {
        self * self
    }
}

But instead of adding impl Square for ... for each type we want to .square(), this impl can be generalised to all types that impl Mul:

impl<T: Mul<Output = T> + Copy> Square for T {
    fn square(&self) -> Self {
        *self * *self
    }
}

The key here is impl<T: ...> Square for T { ... }, that is, for T, the type that the impl takes as parameter. When eventually the constraints on T become too many, they can be moved to a where clause:

impl<T> Square for T
where
    T: Mul<Output = T> + Copy,
{
    fn square(&self) -> Self {
        *self * *self
    }
}

Here's an example of .square() being used for multiple types that already impl Mul:

fn main() {
    println!(
        "{}, {}, {}, {}",
        10u8.square(),
        3u16.square(),
        4u32.square(),
        5u64.square()
    );
}