Struct println中的可变和不可变引用

Struct println中的可变和不可变引用,struct,rust,ownership,Struct,Rust,Ownership,我是一个新手,遇到了一些初学者的问题,我想与互联网上的其他人分享我的解决方案,而我在现有的线程中没有找到这些解决方案。我想知道是否有一种更可靠的方法 我想打印出矩形的高度、宽度和面积 struct Rectangle { height: u32, width: u32, area: u32, } impl Rectangle{ fn area(& mut self) -> u32 { self.area = self.height

我是一个新手,遇到了一些初学者的问题,我想与互联网上的其他人分享我的解决方案,而我在现有的线程中没有找到这些解决方案。我想知道是否有一种更可靠的方法

我想打印出矩形的高度、宽度和面积

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());
}
这给了我一个错误,不能作为不可变的借来,因为它也是作为可变的借来的

我的解决方案

println!("Rectangle has height {1} width {2} and area {0}", rect1.area(), rect1.height, rect1.width);
更改
println中的顺序语句

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

但为什么我的解决方案有效?显然,在同一个println中仍然有一个可变和不可变的引用!语句,但顺序已更改

不!问题是,
area()
需要一个可变借用,但不保留一个,因为它返回一个拥有的值(
u32
),而不是一个借用的值(
&u32
),所以借用只在调用范围内持续,并且在调用返回后释放

现在你可以期待同样的
高度
宽度
,陷阱是
println隐式地借用了它的参数,所以当您
println!(“{}”,rect.height)
它沿着
参数(“,&rect.height”)的行编译成某种东西
,创建一个借阅,直到格式化过程结束

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

块始终是值表达式,并计算值表达式上下文中的最后一个表达式。如果确实需要,可以使用此命令强制移动值

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

println!(“矩形有高度{}宽度{}和面积{},{rect1.height},{rect1.width},rect1.area());
这将首先复制这两个属性,然后是
println
将隐式借用它们,但它不需要借用结构本身,从而导致三个非重叠借用

在这种情况下,您可能需要添加一条注释来解释您为什么这样做,因为它是。。。奇怪

再说一遍,我认为你的
区域是一个反模式,所以YMMV

但为什么我的解决方案有效?显然,在同一个println中仍然有一个可变和不可变的引用!语句,但顺序已更改

不!问题是,
area()
需要一个可变借用,但不保留一个,因为它返回一个拥有的值(
u32
),而不是一个借用的值(
&u32
),所以借用只在调用范围内持续,并且在调用返回后释放

现在你可以期待同样的
高度
宽度
,陷阱是
println隐式地借用了它的参数,所以当您
println!(“{}”,rect.height)
它沿着
参数(“,&rect.height”)的行编译成某种东西
,创建一个借阅,直到格式化过程结束

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

块始终是值表达式,并计算值表达式上下文中的最后一个表达式。如果确实需要,可以使用此命令强制移动值

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

println!(“矩形有高度{}宽度{}和面积{},{rect1.height},{rect1.width},rect1.area());
这将首先复制这两个属性,然后是
println
将隐式借用它们,但它不需要借用结构本身,从而导致三个非重叠借用

在这种情况下,您可能需要添加一条注释来解释您为什么这样做,因为它是。。。奇怪


再说一遍,我认为你的
区域是一个反模式,所以YMMV.

嗯,它甚至不是一个反模式,更像是反常识。我希望这只是这篇文章的一个人为的例子。面积应该在构造时计算(存储和引用),或者在请求时计算(动态计算返回新值,而不是引用)@Rbjz在写评论时,我将面积作为某种懒惰计算的替代品,例如,一些计算成本很高的东西,如果你从未使用过它,你就不想计算它,但一旦计算完毕,您就希望保持该值不变。因此称之为反模式。我同意面积本身毫无意义,因为它是一个相当便宜的计算。好吧,它甚至不是一个反模式,更像是反常识。我希望这只是这篇文章的一个人为的例子。面积应该在构造时计算(存储和引用),或者在请求时计算(动态计算返回新值,而不是引用)@Rbjz在写评论时,我将面积作为某种懒惰计算的替代品,例如,一些计算成本很高的东西,如果你从未使用过它,你就不想计算它,但一旦计算完毕,您就希望保持该值不变。因此称之为反模式。我同意面积本身毫无意义,因为它是一个相当便宜的计算。我不得不说,借用的顺序让我感到有些困难:)Rust在这方面取得了一些进展。我也一样。我不得不说,借款的顺序让我受了几次打击:)Rust在这方面取得了一些进展。我也是。
println!("Rectangle has height {1} width {2} and area {0}", rect1.area(), rect1.height, rect1.width);