如何实现对结构的引用的 Add trait?

我做了一个两个元素的 Vector结构,我想重载 +操作符。

我让所有的函数和方法都接受引用,而不是值,我希望 +操作符也是这样工作的。

impl Add for Vector {
fn add(&self, other: &Vector) -> Vector {
Vector {
x: self.x + other.x,
y: self.y + other.y,
}
}
}

根据我尝试的变体,我可能会遇到生存期问题或类型不匹配。具体来说,&self参数似乎没有被视为正确的类型。

我看过 implAdd上带有模板参数的例子,但它们只会导致不同的错误。

我找到了 如何为不同的 RHS 类型和返回值重载运算符?,但是即使我把 use std::ops::Mul;放在顶部,答案中的代码也不起作用。

我每晚使用 rustc 1.0.0(ed530d7a32015-01-1622:41:16 + 0000)

我不会接受“你只有两个字段,为什么要使用引用”作为答案; 如果我想要一个100个元素的结构呢?我接受这样一个答案: 即使使用大型结构,我也应该通过值传递(如果是这样的话)(但我不认为是这样)我有兴趣了解一个关于 struct 大小和通过 value 与 struct 传递的经验法则,但这不是当前的问题。

25402 次浏览

您需要在 &Vector而不是在 Vector上实现 Add

impl<'a, 'b> Add<&'b Vector> for &'a Vector {
type Output = Vector;


fn add(self, other: &'b Vector) -> Vector {
Vector {
x: self.x + other.x,
y: self.y + other.y,
}
}
}

在其定义中,Add::add总是按值取 self。但是引用和其他 1类似,所以它们也可以实现 trait。当在引用类型上实现 trait 时,self的类型是一个引用; 引用是通过值传递的。通常,在 Rust 中通过值传递意味着转移所有权,但是当引用通过值传递时,它们只是被复制(或者重新借用/移动,如果它是一个可变的引用) ,这并不会转移引用的所有权(因为一个引用本来就不拥有它的引用)。考虑到所有这些,Add::add(和许多其他操作符)通过值获取 self是有意义的: 如果需要获取操作数的所有权,可以直接在 structs/enum 上实现 Add,如果不需要,可以在引用上实现 Add

在这里,self的类型是 &'a Vector,因为这是我们实现 Add的类型。

注意,我还指定了具有不同生存期的 RHS类型参数,以强调这两个输入参数的生存期是不相关的。


1 实际上,引用类型是特殊的,因为你可以为你的机箱中定义的类型实现 trait (也就是说,如果你允许为 T实现 trait,那么你也可以为 &T实现 trait)。&mut TBox<T>具有相同的行为,但是对于 U<T>来说通常不是这样,因为 U不是在同一个板条箱中定义的。

如果要支持所有场景,则必须支持所有组合:

  • & T op U
  • T & U
  • & T op & U
  • 好极了

在生锈的地方,这是通过一个内部宏完成的

幸运的是,有一个生锈的板条箱,意外事件,它也提供了一个宏来为我们编写样板: 板条箱提供了 Impl _ op _ ex!宏,它生成所有的组合。

下面是他们的例子:

#[macro_use] extern crate impl_ops;
use std::ops;


impl_op_ex!(+ |a: &DonkeyKong, b: &DonkeyKong| -> i32 { a.bananas + b.bananas });


fn main() {
let total_bananas = &DonkeyKong::new(2) + &DonkeyKong::new(4);
assert_eq!(6, total_bananas);
let total_bananas = &DonkeyKong::new(2) + DonkeyKong::new(4);
assert_eq!(6, total_bananas);
let total_bananas = DonkeyKong::new(2) + &DonkeyKong::new(4);
assert_eq!(6, total_bananas);
let total_bananas = DonkeyKong::new(2) + DonkeyKong::new(4);
assert_eq!(6, total_bananas);
}

更妙的是,它们还有一个 Impl _ op _ ex _ mutative!,如果您的运算符碰巧是可交换的,它还会生成参数相反的运算符。