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

ano*_*_13 19 operator-overloading rust

给定以下结构:

struct Vector3D {
    x: f32,
    y: f32,
    z: f32
}
Run Code Online (Sandbox Code Playgroud)

*当右边是a时Vector3D,我想重载它的运算符来做一个点积,当RHS是a时,我想重做元素乘法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
    }   
}
Run Code Online (Sandbox Code Playgroud)

编译器说第一个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 { 
...
Run Code Online (Sandbox Code Playgroud)

反之亦然,其他实施.

She*_*ter 29

从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);
}
Run Code Online (Sandbox Code Playgroud)

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


huo*_*uon 12

目前,impl每个特征类型对只允许一个.

这种情况将得到改善RFC 48,但它不是完整的故事(它不是真正的故事的话).相关部分是Coherence,它当然没有特别提到运营商重载案例,并且基本上说它仍然是非法的:

以下示例不正常:

trait Iterator<E> { ... }
impl Iterator<char> for ~str  { ... }
impl Iterator<u8> for ~str { ... }
Run Code Online (Sandbox Code Playgroud)

Niko Matsakis(RFC和Rust类型系统专家的作者)一直在考虑这些超载特征:他是发表的人("如果我想要超载?")下面的诀窍,但他表达了他的厌恶对此,提到他希望允许你编写的实现......

...这是他的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
}
Run Code Online (Sandbox Code Playgroud)

  • 该解决方案似乎已经过时并且会出现编译器错误。Shepmaster 的回答似乎符合要求。 (2认同)