Псевдоним типа для нескольких признаков с типами generi c - PullRequest
2 голосов
/ 12 апреля 2020

Мой вопрос похож на тот, который был рассмотрен в этой проблеме .

Я пытаюсь создать обобщенную c векторную структуру, и у меня работает следующее:

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 , у них есть стандартное значение c type <Rhs = Self> по умолчанию. размер которого не может быть определен во время компиляции, поэтому я не уверен, возможно ли то, что я спрашиваю. Но было бы неплохо, если бы был какой-то обходной путь.

1 Ответ

1 голос
/ 12 апреля 2020

Черта, которую вы ищете, может быть найдена в num-traits crate:

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 может быть построен с любым возможным типом, но Add реализуется, только если T имеет соответствующий Add; то же самое для Sub.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...