Rust DRY черты и дженерики - включая Add и Mul почти идентичны - PullRequest
0 голосов
/ 20 февраля 2020

У меня есть следующий игрушечный код, который использует обобщенные элементы для реализации некоторых операций над трехмерным вектором в виде структуры из 3 обобщенных c элементов.

use std::ops::Add;
use std::ops::Mul;

#[derive(Debug)]
pub struct Vec3<T> {
    x: T,
    y: T,
    z: T,
}

impl<T> Vec3<T> {
    pub fn new(x: T, y: T, z: T) -> Vec3<T> {
        Vec3 { x, y, z }
    }
}

impl<T: Add<Output = T> + Copy> Add<T> for &Vec3<T> {
    type Output = Vec3<T>;
    fn add(self, other: T) -> Vec3<T> {
        Vec3 {
            x: self.x + other,
            y: self.y + other,
            z: self.z + other,
        }
    }
}

impl<T: Add<Output = T> + Copy> Add<&Vec3<T>> for &Vec3<T> {
    type Output = Vec3<T>;
    fn add(self, other: &Vec3<T>) -> Vec3<T> {
        Vec3 {
            x: self.x + other.x,
            y: self.y + other.y,
            z: self.z + other.z,
        }
    }
}

impl<T: Mul<Output = T> + Copy> Mul<T> for &Vec3<T> {
    type Output = Vec3<T>;
    fn mul(self, other: T) -> Vec3<T> {
        Vec3 {
            x: self.x * other,
            y: self.y * other,
            z: self.z * other,
        }
    }
}

impl<T: Mul<Output = T> + Copy> Mul<&Vec3<T>> for &Vec3<T> {
    type Output = Vec3<T>;
    fn mul(self, other: &Vec3<T>) -> Vec3<T> {
        Vec3 {
            x: self.x * other.x,
            y: self.y * other.y,
            z: self.z * other.z,
        }
    }
}

Совершенно очевидно, что я только скопировал и вставил мои impl Add и заменил Add на Mul и переименовал имена методов.

Это небольшое повторение приводит меня к моему вопросу - есть ли что-то в ржавчине, которая также обобщает это? Это что-то вроде общей черты c или, возможно, "мета черты". В моем сценарии соответствующая мета-черта Op будет иметь какой-то метод op. Тогда вместо реализации Add и Mul можно было бы реализовать Op и op вместо операторов + и * соответственно.

Я исследовал и нашел супертрейты но я не могу представить, как их можно использовать, так как я надеюсь, что помимо того, что я представляю, был бы базовый c шаг:

trait Op<T>:Add<T>+Mul<T>{
    fn op(&self)->T;
}

1 Ответ

2 голосов
/ 20 февраля 2020

Относительно вашего вопроса о более общей характеристике для бинарных операций, которая создаст значения Add, Mul et c. для вас: насколько я знаю, нет ни одного, и я думаю, что вы не можете определить это сами из-за бесхозных правил. Вы можете:

  • Написать макрос для бинарных признаков операций
  • Использовать существующий Vector3, например nalgebra , который реализует эти признаки для вас уже
  • Попробуйте обобщить num_derive для работы над структурами с более чем одним членом
...