println 中的可变和不可变引用

Mutable and Immutable reference inside println

我对 Rust 还很陌生,遇到了一些初学者问题,想与互联网上的其他人分享我在现有线程中没有找到的解决方案。我想知道是否有更 Rust 的方法。

我想打印出一个矩形的高、宽和面积。

struct Rectangle {
    height: u32,
    width: u32,
    area: u32,
}

impl Rectangle{
    fn area(& mut self) -> u32 {
        self.area = self.height * self.width;
        return self.area
    }
}

fn main() {
    let mut rect1 = Rectangle {height: 20, width: 30, area: 0};
    println!("Rectangle has height {} width {} and area {}", rect1.height, rect1.width, rect1.area());
}

这给了我错误 cannot borrow as immutable because it is also borrowed as mutable

error[E0502]: cannot borrow `rect1` as mutable because it is also borrowed as immutable
  --> src/main.rs:17:88
   |
17 |     println!("Rectangle has height {} width {} and area {}", rect1.height, rect1.width, rect1.area());
   |     -----------------------------------------------------------------------------------^^^^^^^^^^^^--
   |     |                                                       |                          |
   |     |                                                       |                          mutable borrow occurs here
   |     |                                                       immutable borrow occurs here
   |     immutable borrow later used here

我的解决方案

println!("Rectangle has height {1} width {2} and area {0}", rect1.area(), rect1.height, rect1.width);

更改 println! 语句中的顺序。

我知道您不能同时拥有不可变引用和可变引用,因为不可变引用不希望更改值。参见 here。但为什么我的解决方案有效?显然,在同一个 println! 语句中仍然有一个可变和不可变的引用,但顺序改变了。

But why does my solution work? Clearly, there still is a mutable and immutable reference in the same println! statement but with changed order.

不!问题是 area() 需要一个可变的借用 但不保留一个 ,因为它 returns 是一个拥有的值 (u32) 而不是借用的(&u32),因此借用仅持续调用的范围,并在调用 returns.

后释放

现在你可以期望 heightwidth 相同,陷阱是 println! 隐式地 借用了它的参数,所以当你 println!("{}", rect.height) 它编译成类似于 Arguments("", &rect.height) 的东西,在格式化过程结束之前创建借用。

现在因为借用是隐式的,所以你不能取消引用属性 (*rec.height),因为那将是 &*rec.height,其中 rec.height 仍然是一个 u8,但是有一个另一种方法是 block expressions:

Blocks are always value expressions and evaluate the last expression in value expression context. This can be used to force moving a value if really needed.

这意味着 &{rec.height} 将首先复制(或移动)结构中的值,然后借用该副本。因此,您还可以通过以下方式修复调用:

println!("Rectangle has height {} width {} and area {}", {rect1.height}, {rect1.width}, rect1.area());

这将首先复制两个属性,然后 println! 将隐式借用它们,但不需要借用结构本身导致三个非重叠借用。

在这种情况下,您可能需要添加评论来解释您这样做的原因,因为它...很奇怪。

再一次,我认为你的 area 是一个反模式,所以 YMMV。