英文:
Return ownership from an overloaded operator if Copy trait is unavailable
问题
在包含String
的结构体中(从而阻止了Copy
特性的实现),如果我使用重载的运算符与该结构体一起使用,我将无法再次使用该结构体变量(这是预期的)。但是,我无法弄清楚如何实现自己的Copy
特性或以其他方式解决这个问题。我在运算符中没有修改字符串。
如何从运算符中返回结构体的所有权,以便可以再次使用该结构体?
最小示例:
如果我尝试编译以下代码:
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);
}
我会得到以下错误:
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
英文:
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
答案1
得分: 1
Add
可以用于对类型的引用进行实现。所以,例如,你可以编写如下代码:
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 c = &a + &b;
println!("{}", c);
let c = &c + &a;
println!("{}", c);
}
你也可以实现 Add<&Value> for Value
(或者反过来),这将会消耗其中一个操作数。例如,在标准库中有 impl Add<&str> for String。你必须选择你想要的语义(你是想拥有两个操作数中的哪一个、只有一个,还是都不要)。
然而,我建议仅在只有一个逻辑实现时才覆盖运算符。作为一条经验法则,尽量只在只有一个逻辑实现时“覆盖”运算符,这样当有人尝试使用 Value
时就不会出现意外情况。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论