Overloading an operator by value results in using the moved value

Compiling the following Rust code that uses operator overloading

use std::ops::{Add}; #[derive(Show)] struct Point { x: int, y: int } impl Add for Point { type Output = Point; fn add(self, other: Point) -> Point { Point {x: self.x + other.x, y: self.y + other.y} } } fn main() { let p: Point = Point {x: 1, y: 0}; let pp = p + p; } 

Results in compiler errors due to ownership of p:

 <anon>:21:18: 21:19 error: use of moved value: `p` <anon>:21 let pp = p + p; ^ <anon>:21:14: 21:15 note: `p` moved here because it has type `Point`, which is non-copyable <anon>:21 let pp = p + p; ^ 

The rationale for this is explained here and led to an RFC that was not adopted (partly due to the reasons for the above example). However, later RFCs still introduced byte type signatures for statements.

So far I understand the rationale for the decision. Due to my lack of experience in rust, I am not sure if the “correct” method would allow the above code to work (a) if I do not want to copy, or (b) how to make the structure copyable?

+7
pass-by-value operator-overloading copy rust
source share
2 answers

If you don’t want to copy what my novice understands, you need to implement Add using links to Point .

This will be confirmed by the RFC:

Fortunately, there is no loss in expressiveness, since you can always implement a trait on reference types. However, for types that you want to use by reference, there is a slight loss in ergonomics, as you may need to explicitly borrow operands with &. The surface is that the semantics of ownership become clearer: they are closer to the normal arguments of a function.

And really, this works:

 use std::ops::{Add}; #[derive(Show)] struct Point { x: i32, y: i32 } impl<'a> Add for &'a Point { type Output = Point; fn add(self, other: &'a Point) -> Point { //' Point {x: self.x + other.x, y: self.y + other.y} } } fn main() { let p: Point = Point {x: 1, y: 0}; let pp = &p + &p; println!("{:?}", pp); } 

( playpen )

To copy instead of Point , simply replace #[derive(Show)] with #[derive(Show,Copy)] . Such structures were used for copying by default, but changed .

+4
source share

If your structure cannot be copied (for example, it has a Drop implementation, either by itself or for one of its fields), then it makes sense to create several implementations: value + value, value + link, link + value and link + link. The first three can reuse the memory of one of the operands, and the last can clone one of the operands, and then simply delegate it to existing implementations. Thus, the user of your library can easily decide whether they want to reuse existing values ​​for optimization or not.

In fact, as, for example, BigInt or Complex processed.

However, you can simply make your Point Copy , because copying it is cheap.

+4
source share

All Articles