当使用带有运算符重载的类时,我从简单的辅助方法获得编译错误。这是一个独立的测试(从我的真实代码中简化,但仍然证明了问题):
use std::ops::{Add, Sub, Neg, Mul, Div};
#[derive(Debug, Eq, PartialEq)]
pub struct Money {
cents: i64,
}
impl Money {
pub fn new(cents: i64) -> Money {
Money { cents: cents }
}
}
impl Add for Money {
type Output = Money;
fn add(self, other: Money) -> Money {
Money { cents: self.cents + other.cents }
}
}
impl Mul<Money> for f64 {
type Output = Money;
fn mul(self, rhs: Money) -> Money {
Money { cents: (self * rhs.cents as f64) as i64 }
}
}
#[derive(Debug)]
pub struct AbsOrPerc {
pub absolute: Money,
pub percent: f64,
}
impl AbsOrPerc {
pub fn new(abs: Money, perc: f64) -> AbsOrPerc {
AbsOrPerc {
absolute: abs,
percent: perc,
}
}
pub fn total(&self, basis: Money) -> Money {
// This works:
// Money::new((self.absolute.cents as f64 + self.percent * basis.cents as f64) as i64)
// This doesn't:
self.absolute + self.percent * basis
}
}
我试图用Rust 1.8编译它,但我收到了这个错误:
src/lib.rs:42:5: 42:9 error: cannot move out of borrowed content [E0507]
src/lib.rs:42 self.absolute + self.percent * basis
我已经阅读了Rust Book,以及有关所有权和借来的部分内容。我在StackOverflow上就这个问题阅读了很多问题,例如:
Cannot move out of borrowed content
我不认为我自己的问题是重复的,因为虽然错误是相同的,但情况却不同。此外,如果我知道其他问题如何适用于这个问题,我也不必问。 : - )
所以我的问题是:如何解决此错误?我不想将&self
更改为self
,因为这会导致其他问题。
除了解决问题之外,我还想知道Rust害怕什么。我在这里看不到任何危险。
答案 0 :(得分:8)
您在Money
而不是&Money
上实施运营商。这意味着运营商将获取其操作数的所有权。因此,在total
中,要执行添加,您必须移动self.absolute
,这是不允许的,因为您无法移出借来的指针(您只能移动您拥有的值)。如果类型实现Copy
,那么Rust将复制值(对于i32
或f64
等基元来说就是这种情况;否则,它将移动它们,这意味着移动后源将无法使用。
如果您的Money
结构实际上只包含cents
字段,建议您将其设为Copy
(这也需要实施Clone
,这是一个好主意即使你没有实施Copy
)也要实施。您可以使用Copy
轻松实施Clone
和#[derive]
:
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct Money {
cents: i64,
}
现在,在total
中,Rust不会移动self.absolute
,而是会复制它。如果您无法实施Copy
,请将self.absolute
替换为self.absolute.clone()
。
如果您已在&Money
上实施了运算符,则可以将引用传递给Money
值。例如,通过这样的实现,total
可以像这样实现:
pub fn total(&self, basis: Money) -> Money {
&self.absolute + &(self.percent * &basis)
}