如何为不同的 RHS 类型和返回值重载运算符? [英] How can an operator be overloaded for different RHS types and return values?

查看:14
本文介绍了如何为不同的 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 { 
...

对于其他实现反之亦然.

and vice versa for the other implementation.

推荐答案

目前每个 trait-type 对只允许一个 impl.

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

这种情况将通过RFC 48,但这不是完整的故事(它不是真正的故事).相关部分是Coherence,和它当然没有具体提到运算符重载的情况,并且基本上说它仍然是非法的:

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:

以下示例不正确:

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<...>用于 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天全站免登陆