"无法摆脱借来的内容"与运算符重载

时间:2016-05-19 03:13:09

标签: rust

当使用带有运算符重载的类时,我从简单的辅助方法获得编译错误。这是一个独立的测试(从我的真实代码中简化,但仍然证明了问题):

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害怕什么。我在这里看不到任何危险。

1 个答案:

答案 0 :(得分:8)

您在Money而不是&Money上实施运营商。这意味着运营商将获取其操作数的所有权。因此,在total中,要执行添加,您必须移动self.absolute,这是不允许的,因为您无法移出借来的指针(您只能移动您拥有的值)。如果类型实现Copy,那么Rust将复制值(对于i32f64等基元来说就是这种情况;否则,它将移动它们,这意味着移动后源将无法使用。

如果您的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)
}