具有泛型类型的多个特征的类型别名



我的问题与本期讨论的问题类似。

我正在尝试制作一个通用向量结构,我有以下工作:

use std::ops::{Add, Sub};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Vec2<T> where 
T: Add<Output = T> + Sub<Output = T>
{
pub x: T,
pub y: T,
}
impl<T> Vec2<T> where
T: Add<Output = T>  + Sub<Output = T>
{
pub fn new(x: T, y: T) -> Vec2<T> {
Vec2 { x, y }
}
}
// Overload `+` operator for Vec2
impl<T> Add for Vec2<T> where
T: Add<Output = T>  + Sub<Output = T>
{
type Output = Self;
fn add(self, other: Self) -> Self::Output {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
// Overload `-` operator for Vec2
impl<T> Sub for Vec2<T> where
T: Add<Output = T>  + Sub<Output = T>
{
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}

但正如您所看到的,这个Add<Output = T> + Sub<Output = T>绑定有点混乱,尤其是如果我计划实现更多特性的话。有没有什么方法可以使用宏或键入别名,这样我就可以做一些类似的事情

trait Num: Add + Sub {}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Vec2<T> where 
T: Num
{
...
}
// Overload `+` operator for Vec2
impl<T> Add for Vec2<T> where
T: Num
{
...
}

注意:可以理解,上面的代码会产生编译错误。如果您查看std::ops:Add或std::ops::Sub-tacts的文档,它们有一个默认的泛型类型<Rhs = Self>,其大小在编译时无法确定,所以我不确定我所问的是否可能。但如果有一些变通办法就好了。

您正在寻找的特征可以在num个特征板条箱中找到:

pub trait NumOps<Rhs = Self, Output = Self>:
Add<Rhs, Output = Output>
+ Sub<Rhs, Output = Output>
+ Mul<Rhs, Output = Output>
+ Div<Rhs, Output = Output>
+ Rem<Rhs, Output = Output>
{
}
impl<T, Rhs, Output> NumOps<Rhs, Output> for T where
T: Add<Rhs, Output = Output>
+ Sub<Rhs, Output = Output>
+ Mul<Rhs, Output = Output>
+ Div<Rhs, Output = Output>
+ Rem<Rhs, Output = Output>
{
}

你可以很容易地在你的矢量类型中使用它:

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Vec2<T: NumOps> {
pub x: T,
pub y: T,
}
impl<T: NumOps> Add for Vec2<T> {
type Output = Self;
fn add(self, other: Self) -> Self::Output {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}

操场上的完整代码。

但实际上,将每一个特征都缩小到最低限度是一种更好的做法:

// No trait bound on T: Vec2 can store any type
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct Vec2<T> {
pub x: T,
pub y: T,
}
impl<T> Vec2<T> {
pub fn new(x: T, y: T) -> Vec2<T> {
Vec2 { x, y }
}
}
// Implement `+` operator for Vec2<T> only if T has it
impl<T> Add for Vec2<T>
where T: Add<T, Output = T>
{
type Output = Self;
fn add(self, other: Self) -> Self::Output {
Self {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
// Implement `-` operator for Vec2<T> only if T has it
impl<T> Sub for Vec2<T>
where T: Sub<T, Output = T>
{
type Output = Self;
fn sub(self, other: Self) -> Self::Output {
Self {
x: self.x - other.x,
y: self.y - other.y,
}
}
}

操场上的完整代码。

这样,Vec2可以用任何可能的类型构造,但只有当T具有相应的Add时,才实现Add;与CCD_ 6相同。

最新更新