如何在Rust中实现双向LHS和RHS操作符?

如何在Rust中实现双向LHS和RHS操作符?,rust,Rust,在Rust中,可以重载运算符(+,-,/,*,+=等)。我的Vec3类型有一个简单的add实现: use std::ops::Add; struct Vec3 { e0: f32, e1: f32, e2: f32, } impl Add<f32> for &Vec3 { type Output = Vec3; fn add(self, other: f32) -> Vec3 { Vec3 {

在Rust中,可以重载运算符(
+
-
/
*
+=
等)。我的
Vec3
类型有一个简单的add实现:

use std::ops::Add;

struct Vec3 {
    e0: f32,
    e1: f32,
    e2: f32,
}

impl Add<f32> for &Vec3 {
    type Output = Vec3;

    fn add(self, other: f32) -> Vec3 {
        Vec3 {
            e0: self.e0 + other,
            e1: self.e1 + other,
            e2: self.e2 + other,
        }
    }
}
但以另一种方式操作会出错:

let this_wont_compile = 43f32 + my_vec_3;
错误[E0277]:无法将'Vec3'添加到'f32'`
-->src/lib.rs:23:35
|
23 |让这个_won_compile=43f32+my_vec_3;
|^f32+Vec3没有实现`
|
=help:trait`std::ops::Add`未为`f32实现`
我知道我可以为f32编写一个
impl-Add的实现,但这正是我想要自动化的


如何编写实现,使
LHS
RHS
可以互换?在Rust中可能吗?

该语言不会为您自动执行此操作

你的选择是:

  • 自己编写实现
  • 构建并使用元编程
  • zrzka非常友好地构建了一个为这个特定用例提供宏示例的框架

    这也提供了一些有用的提示,因为它本身使用这些宏来自动化一些繁琐的工作

    我担心的一个问题是,如果我使用宏,我必须将其称为内联宏(如
    vec![]
    )。由于宏是在编译时展开的,所以宏将为您生成可以正常调用的函数。RLS仍将提供语法支持,一切都将按照您的预期工作

    这是我最终使用的实现。我相信还有更多的东西可以自动化(一个是向前看),但我很满意

    /// Generates the operations for vector methods. `let result = my_vec_3 + my_other_vec3`
    /// Handles `Vec3, Vec3`, `Vec3, &Vec3`, `&Vec3, Vec3`, `&Vec3, &Vec3`
    /// `vec3_vec3_op(ops::AddAssign, add_assign)` (note the camelcase add_assign name)
    macro_rules! vec3_vec3_op {
        ($($path:ident)::+, $fn:ident) => {
            impl $($path)::+<Vec3> for Vec3 {
                type Output = Vec3;
    
                fn $fn(self, other: Vec3) -> Self::Output {
                    Vec3 {
                        e0: self.e0.$fn(other.e0),
                        e1: self.e1.$fn(other.e1),
                        e2: self.e2.$fn(other.e2),
                    }
                }
            }
    
            impl $($path)::+<&Vec3> for &Vec3 {
                type Output = Vec3;
    
                fn $fn(self, other: &Vec3) -> Self::Output {
                    Vec3 {
                        e0: self.e0.$fn(other.e0),
                        e1: self.e1.$fn(other.e1),
                        e2: self.e2.$fn(other.e2),
                    }
                }
            }
    
            impl $($path)::+<&Vec3> for Vec3 {
                type Output = Vec3;
    
                fn $fn(self, other: &Vec3) -> Self::Output {
                    Vec3 {
                        e0: self.e0.$fn(other.e0),
                        e1: self.e1.$fn(other.e1),
                        e2: self.e2.$fn(other.e2),
                    }
                }
            }
    
            impl $($path)::+<Vec3> for &Vec3 {
                type Output = Vec3;
    
                fn $fn(self, other: Vec3) -> Self::Output {
                    Vec3 {
                        e0: self.e0.$fn(other.e0),
                        e1: self.e1.$fn(other.e1),
                        e2: self.e2.$fn(other.e2),
                    }
                }
            }
        };
    }
    
    /// Generates the operations for vector method assignment. `my_vec += my_other_vec`
    /// Handles `Vec3, Vec3` and `Vec3, &Vec3`
    /// `vec3_vec3_opassign(ops::AddAssign, add_assign)` (note the camelcase add_assign name)
    macro_rules! vec3_vec3_opassign {
        ($($path:ident)::+, $fn:ident) => {
            impl $($path)::+<Vec3> for Vec3 {
                fn $fn(&mut self, other: Vec3) {
                    self.e0.$fn(other.e0);
                    self.e1.$fn(other.e1);
                    self.e2.$fn(other.e2);
                }
            }
    
            impl $($path)::+<&Vec3> for Vec3 {
                fn $fn(&mut self, other: &Vec3) {
                    self.e0.$fn(other.e0);
                    self.e1.$fn(other.e1);
                    self.e2.$fn(other.e2);
                }
            }
        };
    }
    
    /// Generates the operations for method assignment. `my_vec += f32`
    /// `vec3_opassign(ops:AddAssign, add_assign)` (note the camelcase add_assign name)
    macro_rules! vec3_opassign {
        ($($path:ident)::+, $fn:ident, $ty:ty) => {
            impl $($path)::+<$ty> for Vec3 {
                fn $fn(&mut self, other: $ty) {
                    self.e0.$fn(other);
                    self.e1.$fn(other);
                    self.e2.$fn(other);
                }
            }
        }
    }
    
    /// Generates the operations for the method. `let result = my_vec + 4f32`
    /// Handles `Vec3, T`, `T, Vec3`, `&Vec3, T`, `T, &Vec3`
    /// `vec3_op!(ops:Add, add, f32)`
    macro_rules! vec3_op {
        ($($path:ident)::+, $fn:ident, $ty:ty) => {
            // impl ops::Add::add for Vec3
            impl $($path)::+<$ty> for Vec3 {
                type Output = Vec3;
    
                // fn add(self, other: f32) -> Self::Output
                fn $fn(self, other: $ty) -> Self::Output {
                    Vec3 {
                        // e0: self.e0.add(other)
                        e0: self.e0.$fn(other),
                        e1: self.e1.$fn(other),
                        e2: self.e2.$fn(other),
                    }
                }
            }
    
            impl $($path)::+<$ty> for &Vec3 {
                type Output = Vec3;
    
                fn $fn(self, other: $ty) -> Self::Output {
                    Vec3 {
                        e0: self.e0.$fn(other),
                        e1: self.e1.$fn(other),
                        e2: self.e2.$fn(other),
                    }
                }
            }
    
            impl $($path)::+<Vec3> for $ty {
                type Output = Vec3;
    
                fn $fn(self, other: Vec3) -> Self::Output {
                    Vec3 {
                        e0: self.$fn(other.e0),
                        e1: self.$fn(other.e1),
                        e2: self.$fn(other.e2),
                    }
                }
            }
    
            impl $($path)::+<&Vec3> for $ty {
                type Output = Vec3;
    
                fn $fn(self, other: &Vec3) -> Self::Output {
                    Vec3 {
                        e0: self.$fn(other.e0),
                        e1: self.$fn(other.e1),
                        e2: self.$fn(other.e2),
                    }
                }
            }
        }
    }
    
    macro_rules! vec3_op_for {
        ($ty: ty) => {
            vec3_op!(ops::Add, add, $ty);
            vec3_op!(ops::Sub, sub, $ty);
            vec3_op!(ops::Mul, mul, $ty);
            vec3_op!(ops::Div, div, $ty);
            vec3_opassign!(ops::AddAssign, add_assign, $ty);
            vec3_opassign!(ops::SubAssign, sub_assign, $ty);
            vec3_opassign!(ops::MulAssign, mul_assign, $ty);
            vec3_opassign!(ops::DivAssign, div_assign, $ty);
        };
    }
    
    vec3_vec3_op!(ops::Add, add);
    vec3_vec3_op!(ops::Sub, sub);
    vec3_vec3_op!(ops::Mul, mul);
    vec3_vec3_op!(ops::Div, div);
    vec3_vec3_opassign!(ops::AddAssign, add_assign);
    vec3_vec3_opassign!(ops::SubAssign, sub_assign);
    vec3_vec3_opassign!(ops::MulAssign, mul_assign);
    vec3_vec3_opassign!(ops::DivAssign, div_assign);
    vec3_op_for!(f32);
    
    ///生成向量方法的操作`让结果=我的向量3+我的其他向量3`
    ///处理'Vec3,Vec3','Vec3,&Vec3',`&Vec3,Vec3`,`&Vec3,&Vec3``
    ///`vec3_vec3_op(ops::AddAssign,add_assign)`(注意camelcase add_assign名称)
    宏规则!vec3_vec3_op{
    ($($path:ident):+,$fn:ident)=>{
    impl$($path)::+用于Vec3{
    类型输出=Vec3;
    fn$fn(self,other:Vec3)->self::Output{
    Vec3{
    e0:self.e0.$fn(其他.e0),
    e1:自身e1.$fn(其他e1),
    e2:self.e2.$fn(其他.e2),
    }
    }
    }
    impl$($path)::+for&Vec3{
    类型输出=Vec3;
    fn$fn(self,other:&Vec3)->self::Output{
    Vec3{
    e0:self.e0.$fn(其他.e0),
    e1:自身e1.$fn(其他e1),
    e2:self.e2.$fn(其他.e2),
    }
    }
    }
    impl$($path)::+用于Vec3{
    类型输出=Vec3;
    fn$fn(self,other:&Vec3)->self::Output{
    Vec3{
    e0:self.e0.$fn(其他.e0),
    e1:自身e1.$fn(其他e1),
    e2:self.e2.$fn(其他.e2),
    }
    }
    }
    impl$($path)::+for&Vec3{
    类型输出=Vec3;
    fn$fn(self,other:Vec3)->self::Output{
    Vec3{
    e0:self.e0.$fn(其他.e0),
    e1:自身e1.$fn(其他e1),
    e2:self.e2.$fn(其他.e2),
    }
    }
    }
    };
    }
    ///生成向量方法赋值的操作`my_vec+=my_other_vec`
    ///处理'Vec3,Vec3'和'Vec3,&Vec3'`
    ///`vec3_vec3_opassign(ops::AddAssign,add_assign)`(注意camelcase add_assign名称)
    宏规则!vec3_vec3_opassign{
    ($($path:ident):+,$fn:ident)=>{
    impl$($path)::+用于Vec3{
    fn$fn(&mut self,其他:Vec3){
    自售0.0.$fn(其他0.0);
    自身e1.$fn(其他e1);
    自身e2.$fn(其他e2);
    }
    }
    impl$($path)::+用于Vec3{
    fn$fn(&mut self,other:&Vec3){
    自售0.0.$fn(其他0.0);
    自身e1.$fn(其他e1);
    自身e2.$fn(其他e2);
    }
    }
    };
    }
    ///生成方法分配的操作`my_vec+=f32`
    ///`vec3_opassign(ops:AddAssign,add_assign)`(注意camelcase add_assign名称)
    宏规则!向量3_opassign{
    ($($path:ident):+,$fn:ident,$ty:ty)=>{
    impl$($path)::+用于Vec3{
    fn$fn(&M自我,其他:$ty){
    自付0.0美元fn(其他);
    自用e1.$fn(其他);
    自我评价e2.$fn(其他);
    }
    }
    }
    }
    ///生成方法的操作`让结果=my_vec+4f32`
    ///处理`Vec3,T`,`T,Vec3`,`&Vec3,T`,`T,&Vec3``
    ///“韦克!(操作:添加,添加,f32)`
    宏规则!vec3_op{
    ($($path:ident):+,$fn:ident,$ty:ty)=>{
    //impl ops::Add::为Vec3添加
    impl$($path)::+用于Vec3{
    类型输出=Vec3;
    //fn add(self,other:f32)->self::Output
    fn$fn(self,other:$ty)->self::Output{
    Vec3{
    //e0:self.e0.add(其他)
    e0:自身e0.$fn(其他),
    e1:自身e1.$fn(其他),
    e2:自身e2.$fn(其他),
    }
    }
    }
    impl$($path)::+for&Vec3{
    类型输出=Vec3;
    fn$fn(self,other:$ty)->self::Output{
    Vec3{
    e0:自身e0.$fn(其他),
    e1:自身e1.$fn(其他),
    e2:自身e2.$fn(其他),
    }
    }
    }
    impl$($path)::+for$ty{
    类型输出=Vec3;
    fn$fn(self,other:Vec3)->self::Output{
    Vec3{
    e0:自身$fn(其他.e0),
    e1:自身$fn(其他e1),
    e2:self.$fn(其他e2),
    }
    }
    }
    impl$($path)::+for$ty{
    类型输出=Vec3;
    fn$fn(self,other:&Vec3)->self::Outp
    
    /// Generates the operations for vector methods. `let result = my_vec_3 + my_other_vec3`
    /// Handles `Vec3, Vec3`, `Vec3, &Vec3`, `&Vec3, Vec3`, `&Vec3, &Vec3`
    /// `vec3_vec3_op(ops::AddAssign, add_assign)` (note the camelcase add_assign name)
    macro_rules! vec3_vec3_op {
        ($($path:ident)::+, $fn:ident) => {
            impl $($path)::+<Vec3> for Vec3 {
                type Output = Vec3;
    
                fn $fn(self, other: Vec3) -> Self::Output {
                    Vec3 {
                        e0: self.e0.$fn(other.e0),
                        e1: self.e1.$fn(other.e1),
                        e2: self.e2.$fn(other.e2),
                    }
                }
            }
    
            impl $($path)::+<&Vec3> for &Vec3 {
                type Output = Vec3;
    
                fn $fn(self, other: &Vec3) -> Self::Output {
                    Vec3 {
                        e0: self.e0.$fn(other.e0),
                        e1: self.e1.$fn(other.e1),
                        e2: self.e2.$fn(other.e2),
                    }
                }
            }
    
            impl $($path)::+<&Vec3> for Vec3 {
                type Output = Vec3;
    
                fn $fn(self, other: &Vec3) -> Self::Output {
                    Vec3 {
                        e0: self.e0.$fn(other.e0),
                        e1: self.e1.$fn(other.e1),
                        e2: self.e2.$fn(other.e2),
                    }
                }
            }
    
            impl $($path)::+<Vec3> for &Vec3 {
                type Output = Vec3;
    
                fn $fn(self, other: Vec3) -> Self::Output {
                    Vec3 {
                        e0: self.e0.$fn(other.e0),
                        e1: self.e1.$fn(other.e1),
                        e2: self.e2.$fn(other.e2),
                    }
                }
            }
        };
    }
    
    /// Generates the operations for vector method assignment. `my_vec += my_other_vec`
    /// Handles `Vec3, Vec3` and `Vec3, &Vec3`
    /// `vec3_vec3_opassign(ops::AddAssign, add_assign)` (note the camelcase add_assign name)
    macro_rules! vec3_vec3_opassign {
        ($($path:ident)::+, $fn:ident) => {
            impl $($path)::+<Vec3> for Vec3 {
                fn $fn(&mut self, other: Vec3) {
                    self.e0.$fn(other.e0);
                    self.e1.$fn(other.e1);
                    self.e2.$fn(other.e2);
                }
            }
    
            impl $($path)::+<&Vec3> for Vec3 {
                fn $fn(&mut self, other: &Vec3) {
                    self.e0.$fn(other.e0);
                    self.e1.$fn(other.e1);
                    self.e2.$fn(other.e2);
                }
            }
        };
    }
    
    /// Generates the operations for method assignment. `my_vec += f32`
    /// `vec3_opassign(ops:AddAssign, add_assign)` (note the camelcase add_assign name)
    macro_rules! vec3_opassign {
        ($($path:ident)::+, $fn:ident, $ty:ty) => {
            impl $($path)::+<$ty> for Vec3 {
                fn $fn(&mut self, other: $ty) {
                    self.e0.$fn(other);
                    self.e1.$fn(other);
                    self.e2.$fn(other);
                }
            }
        }
    }
    
    /// Generates the operations for the method. `let result = my_vec + 4f32`
    /// Handles `Vec3, T`, `T, Vec3`, `&Vec3, T`, `T, &Vec3`
    /// `vec3_op!(ops:Add, add, f32)`
    macro_rules! vec3_op {
        ($($path:ident)::+, $fn:ident, $ty:ty) => {
            // impl ops::Add::add for Vec3
            impl $($path)::+<$ty> for Vec3 {
                type Output = Vec3;
    
                // fn add(self, other: f32) -> Self::Output
                fn $fn(self, other: $ty) -> Self::Output {
                    Vec3 {
                        // e0: self.e0.add(other)
                        e0: self.e0.$fn(other),
                        e1: self.e1.$fn(other),
                        e2: self.e2.$fn(other),
                    }
                }
            }
    
            impl $($path)::+<$ty> for &Vec3 {
                type Output = Vec3;
    
                fn $fn(self, other: $ty) -> Self::Output {
                    Vec3 {
                        e0: self.e0.$fn(other),
                        e1: self.e1.$fn(other),
                        e2: self.e2.$fn(other),
                    }
                }
            }
    
            impl $($path)::+<Vec3> for $ty {
                type Output = Vec3;
    
                fn $fn(self, other: Vec3) -> Self::Output {
                    Vec3 {
                        e0: self.$fn(other.e0),
                        e1: self.$fn(other.e1),
                        e2: self.$fn(other.e2),
                    }
                }
            }
    
            impl $($path)::+<&Vec3> for $ty {
                type Output = Vec3;
    
                fn $fn(self, other: &Vec3) -> Self::Output {
                    Vec3 {
                        e0: self.$fn(other.e0),
                        e1: self.$fn(other.e1),
                        e2: self.$fn(other.e2),
                    }
                }
            }
        }
    }
    
    macro_rules! vec3_op_for {
        ($ty: ty) => {
            vec3_op!(ops::Add, add, $ty);
            vec3_op!(ops::Sub, sub, $ty);
            vec3_op!(ops::Mul, mul, $ty);
            vec3_op!(ops::Div, div, $ty);
            vec3_opassign!(ops::AddAssign, add_assign, $ty);
            vec3_opassign!(ops::SubAssign, sub_assign, $ty);
            vec3_opassign!(ops::MulAssign, mul_assign, $ty);
            vec3_opassign!(ops::DivAssign, div_assign, $ty);
        };
    }
    
    vec3_vec3_op!(ops::Add, add);
    vec3_vec3_op!(ops::Sub, sub);
    vec3_vec3_op!(ops::Mul, mul);
    vec3_vec3_op!(ops::Div, div);
    vec3_vec3_opassign!(ops::AddAssign, add_assign);
    vec3_vec3_opassign!(ops::SubAssign, sub_assign);
    vec3_vec3_opassign!(ops::MulAssign, mul_assign);
    vec3_vec3_opassign!(ops::DivAssign, div_assign);
    vec3_op_for!(f32);