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 {}