如何为不同的RHS类型和返回值超载操作员? [英] How can an operator be overloaded for different RHS types and return values?

查看:82
本文介绍了如何为不同的RHS类型和返回值超载操作员?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

给出以下结构:

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

我想重载它的*运算符以在右侧为Vector3D时进行点积运算,并在RHS为f32时进行按元素乘法.我的代码如下:

I want to overload its * operator to do a dot product when the right hand side is a Vector3D, and to do an element-wise multiplication when the RHS is a f32. My code looks like this:

// 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块说:

The compiler says for the first impl block:

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 { 
...

反之亦然.

推荐答案

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

At the moment only a single impl is allowed per trait-type pair.

使用一致性,并且它当然没有特别提到运算符重载的情况,实质上说它仍然是非法的:

This situation will be improved with RFC 48, but it's not the full story (it's not really any of the story). The relevant section is Coherence, and it certainly doesn't mention the operator overloading case specifically, and essentially says it is still illegal:

以下示例不正确:

The following example is NOT OK:

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

Niko Matsakis(该RFC和Rust类型系统专家的作者)一直在特别考虑这些超载特征:他是

Niko Matsakis (author of that RFC & Rust-type-system expert) has been thinking about these overloading traits specifically: he is the one who published ("What if I want overloading?") the trick below, but he has expressed his distaste towards it, mentioning that he'd like to allow implementations as you have written...

...,这是他的 RFC 135 进入.有关情况,请参见.

... which is where his RFC 135 comes in. The situation is described in detail in "multidispatch traits".

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

You can work-around it for now using secondary traits. The extra layer of traits allows you to write just one impl Mul<...> for Vector3D but comes at the cost of requiring a new trait for each type for which you wish to have multiple implementations of 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
}

这篇关于如何为不同的RHS类型和返回值超载操作员?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆