With a struct that contains a String
(thus preventing implementation of Copy
trait), if I use the struct with an overloaded operator, I am unable to use the struct variable again (which is expected). However, I am unable to figure out how to implement my own Copy
trait or work around this in some other way. I am not modifying the string in the operator at all.
How do I return the ownership of a struct from an operator such that the struct can be used again?
Minimal Case:
If I try to compile the following code:
use std::ops;
struct Value {
val: i32,
name: String
}
impl std::fmt::Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}({})", self.name, self.val)
}
}
impl ops::Add<Value> for Value {
type Output = Value;
fn add(self, _rhs: Value) -> Value {
Value { val: self.val + _rhs.val,
name: format!("({}+{})", self.name, _rhs.name) }
}
}
fn main() {
let a = Value {val: 5, name: "a".to_string()};
let b = Value {val: 6, name: "b".to_string()};
let mut c = a + b;
c = c + a;
println!("{}", c);
}
I get the following error:
error[E0382]: use of moved value: `a`
--> src/main.rs:29:13
|
24 | let a = Value {val: 5, name: "a".to_string()};
| - move occurs because `a` has type `Value`, which does not implement the `Copy` trait
...
27 | let mut c = a + b;
| ----- `a` moved due to usage in operator
28 |
29 | c = c + a;
| ^ value used here after move
|
note: calling this operator moves the left-hand side
Add
can be implemented for references to types too. So for example you could write something like this:
impl ops::Add<&Value> for &Value {
type Output = Value;
fn add(self, _rhs: &Value) -> Value {
Value { val: self.val + _rhs.val,
name: format!("({}+{})", self.name, _rhs.name) }
}
}
and use it like this:
fn main() {
let a = Value {val: 5, name: "a".to_string()};
let b = Value {val: 6, name: "b".to_string()};
let c = &a + &b;
println!("{}", c);
let c = &c + &a;
println!("{}", c);
}
You can also implement Add<&Value> for Value
(or vice versa) which will consume one operand. For example in standard library there is impl Add<&str> for String. You have to choose which semantics you want (do you want to take ownership of both operands, only one, or neither).
However I would suggest to just use normal methods as it won't result in surprises when someone tries to use Value
. As a rule of thumb try to "override" operators only when there is only one logical implementation.