Home > other >  Do I need to manually rewrite all the trait bounds for every impl block in my Rust code if I defined
Do I need to manually rewrite all the trait bounds for every impl block in my Rust code if I defined

Time:09-27

struct Vec2<T: Sub<Output = T>   Add<Output = T>   Copy> {
    x: T,
    y: T
}

impl<T: Sub<Output = T>   Add<Output = T>   Copy> Add for Vec2<T> {
    type Output = Vec2<T>;
    fn add(self, rhs: Self) -> Self::Output {
        Vec2 {
            x: self.x   rhs.x,
            y: self.y   rhs.y
        }
    }
}

Do I need to rewrite this not-so-beautiful <T: Sub<Output = T> Add<Output = T> Copy> every time, or is there another, more elegant method that I am not familiar with?

I know one hack that can achive behaviour that I want by douing like so:

trait Numeric<T> : Sub<Output = T>   Add<Output = T>   Copy {}

macro_rules! add_impl {
    ($($t:ty)*) => ($(
        impl Numeric<$t> for $t {}
    )*)
}

add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 }

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

impl<T: Numeric<T>> Add for Vec2<T> {
    type Output = Vec2<T>;
    fn add(self, rhs: Self) -> Self::Output {
        Vec2 {
            x: self.x   rhs.x,
            y: self.y   rhs.y
        }
    }
}

This, while partially solving my problem, looks even messier in my opinion.

And I know that "you shoud not put trait bounds in the struct definition", but i really want the compiler to give an error if the end user will try to:

let v = Vec2 {
        x: "Hello", // ERROR WANTED HERE
        y: "World"
    };

CodePudding user response:

Trait aliases are unstable, but if you are using a nightly toolchain, you can alias your long trait bounds into a shorter one to actually specify in your impl blocks:

#![feature(trait_alias)]

use core::ops::{Add, Sub};

trait Numeric<T> = Sub<Output = T>   Add<Output = T>   Copy;

struct Vec2<T: Numeric<T>> {
    x: T,
    y: T
}

impl<T: Numeric<T>> Add for Vec2<T> {
    type Output = Vec2<T>;
    fn add(self, rhs: Self) -> Self::Output {
        Vec2 {
            x: self.x   rhs.x,
            y: self.y   rhs.y
        }
    }
}

A more normal method of implementing your second approach is to just impl Numeric for all types satisfying a trait bound, which removes the need for your macros:

impl<T> Numeric<T> for T where T: Sub<Output = T>   Add<Output = T>   Copy {}
  • Related