如何为不同的RHS类型和返回值重载运算符?

时间:2014-07-06 09:20:47

标签: operator-overloading rust

给出以下结构:

struct Vector3D {
    x: f32,
    y: f32,
    z: f32
}

我希望重叠其*运算符以在右侧为Vector3D时执行点积,并在RHS为f32时执行逐元素乘法运算。我的代码如下所示:

// Multiplication with scalar
impl Mul<f32, Vector3D> for Vector3D {
    fn mul(&self, f: &f32) -> Vector3D {
        Vector3D {x: self.x * *f, y: self.y * *f, z: self.z * *f} 
    }   
}
// Multiplication with vector, aka dot product
impl Mul<Vector3D, f32> for Vector3D {
    fn mul(&self, other: &Vector3D) -> f32 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }   
}

编译器说第一个impl块:

Vector3D.rs:40:1: 44:2 error: conflicting implementations for trait `std::ops::Mul`
Vector3D.rs:40 impl Mul<f32, Vector3D> for Vector3D { 
...
Vector3D.rs:53:1: 57:2 note: note conflicting implementation here
Vector3D.rs:53 impl Mul<Vector3D, f32> for Vector3D { 
...

,反之亦然,其他实施。

2 个答案:

答案 0 :(得分:27)

从Rust 1.0开始,您现在可以实现此目的:

use std::ops::Mul;

#[derive(Copy, Clone, PartialEq, Debug)]
struct Vector3D {
    x: f32,
    y: f32,
    z: f32,
}

// Multiplication with scalar
impl Mul<f32> for Vector3D {
    type Output = Vector3D;

    fn mul(self, f: f32) -> Vector3D {
        Vector3D {
            x: self.x * f,
            y: self.y * f,
            z: self.z * f,
        }
    }
}

// Multiplication with vector, aka dot product
impl Mul<Vector3D> for Vector3D {
    type Output = f32;

    fn mul(self, other: Vector3D) -> f32 {
        self.x * other.x + self.y * other.y + self.z * other.z
    }
}

fn main() {
    let a = Vector3D {
        x: 1.0,
        y: 2.0,
        z: 3.0,
    };
    let b = a * -1.0;
    let c = a * b;

    println!("{:?}", a);
    println!("{:?}", b);
    println!("{:?}", c);
}

允许这一点的重大变化是引入了关联类型,它在每个实现中显示为type Output =位。另一个值得注意的变化是,运算符traits现在按值使用参数,消耗它们,所以我继续为结构实现Copy

答案 1 :(得分:12)

目前每个特质类型对只允许一个impl

这种情况将随着RFC 48进行改进,但这不是完整的故事(它不是真正的故事)。相关部分是Coherence,它当然没有具体提到运营商超载情况,并且基本上说它仍然是非法的:

  

以下示例不正常:

trait Iterator<E> { ... }
impl Iterator<char> for ~str  { ... }
impl Iterator<u8> for ~str { ... }

Niko Matsakis(RFC&amp; Rust类型系统专家的作者)一直在考虑这些超载特征:他是published(“如果我想要超载怎么办?”)的伎俩下面,但他表达了他对此的厌恶,并提到他希望允许实施,因为你已经写了......

...这是RFC 135进入的地方。"multidispatch traits"中详细介绍了这种情况。


您现在可以使用辅助特征来解决它。额外的特征层允许您只编写一个impl Mul<...> for Vector3D,但代价是需要为您希望多个Mul实现的每种类型设置一个新特征。

#[deriving(Show)]
struct Vector3D {
    x: f32,
    y: f32,
    z: f32
}

trait MulVec3D<Res> {
    fn do_mul(&self, v: &Vector3D) -> Res;
}

// Multiplication with scalar
impl MulVec3D<Vector3D> for f32 {
   fn do_mul(&self, v: &Vector3D) -> Vector3D {
       Vector3D {x: v.x * *self, y: v.y * *self, z: v.z * *self} 
   }
}
// Multiplication with vector, aka dot product
impl MulVec3D<f32> for Vector3D {
    fn do_mul(&self, v: &Vector3D) -> f32 {
        self.x * v.x + self.y * v.y + self.z * v.z
    }
}

impl<Res, RHS: MulVec3D<Res>>  Mul<RHS, Res> for Vector3D {
    fn mul(&self, rhs: &RHS) -> Res {
        rhs.do_mul(self)
    }   
}

fn main() {
    let a = Vector3D { x: 1.0, y: 2.0, z: 3.0 };
    let b = Vector3D { x: -3.0, y: 2.0, z: -1.0 };

    println!("{}, {}", a * 2f32, a * b); // Vector3D { x: 2, y: 4, z: 6 }, -2
}