简体   繁体   中英

Rust DRY traits and generics - impl Add and Mul nearly identical

I have the following toy code which makes use of generics to implement some operations on a 3d vector as a struct of 3 generic elements.

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

It's pretty plain to see that all I did was copy and paste my impl Add 's and replace Add for Mul and renamed the method names.

This slight repetition brings me to my question - Is there something in rust which generalizes this as well? That is something akin to a generic trait or perhaps "meta trait". In my scenario, a relevant "meta trait" Op would have some method op . Then, instead of implementing Add and Mul , one would implement Op and op would take the place of the + and * operators respectively.

I explored and found supertraits but I cannot imagine how they could be used as I hope beyond what I imagine would be the basic step:

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

Regarding your question for a more general trait for binary operations that will create impls of Add, Mul etc. for you: There is none as far as I'm aware, and I think you cannot define it yourself because of orphan rules. You could:

  • Write a macro for binary ops traits
  • Use an existing Vector3, like nalgebra 's which implements those traits for you already
  • Try to generalize num_derive to work on structs with more than one member

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM