如果我在结构块中定义了Rust代码中的每个impl块,我是否需要手动重写它的所有特征边界


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

我需要每次重写这个不那么漂亮的<T: Sub<Output = T> + Add<Output = T> + Copy>吗?还是还有另一种我不熟悉的更优雅的方法?

我知道一个黑客可以通过这样的方式实现我想要的行为:

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

在我看来,这虽然部分解决了我的问题,但看起来更混乱。

我知道";你不应该在结构定义中设置特征边界";,但我真的希望编译器给出一个错误,如果最终用户会尝试:

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

特性别名是不稳定的,但如果您使用夜间工具链,您可以将长特性边界别名为一个较短的边界,以便在impl块中实际指定:

#![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
}
}
}

实现第二种方法的一种更正常的方法是,对于满足特性界限的所有类型,只使用impl Numeric,这样就不需要宏了:

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

最新更新