Fel*_*ter 15 immutability mutability rust
首先,让代码说:
#[derive(Debug)]
struct Bar;
#[derive(Debug)]
struct Qux {
baz: bool
}
#[derive(Debug)]
struct Foo {
bars: Vec<Bar>,
qux: Qux,
}
impl Foo {
fn get_qux(&mut self) -> &mut Qux {
&mut self.qux
}
fn run(&mut self) {
// 1. Fails:
let mut qux = self.get_qux();
// 2. Works:
// let mut qux = &mut Qux { baz: false };
// 3. Works:
// let mut qux = &mut self.qux;
let qux_mut = &mut qux;
qux_mut.baz = true;
for bar in &self.bars {
println!("{:?}", bar);
}
}
}
fn main() {
println!("Hello, world!");
let mut foo = Foo { bars: vec!(), qux: Qux { baz: false } };
foo.run();
}
Run Code Online (Sandbox Code Playgroud)
这个错误:
error[E0502]: cannot borrow `self.bars` as immutable because `*self` is also borrowed as mutable
--> src/main.rs:33:21
|
22 | let mut qux = self.get_qux();
| ---- mutable borrow occurs here
...
33 | for bar in &self.bars {
| ^^^^^^^^^ immutable borrow occurs here
...
36 | }
| - mutable borrow ends here
Run Code Online (Sandbox Code Playgroud)
如果我取消或者2.还是3.,为什么它编译就好了?被调用的函数1.没有做任何与2.or 完全不同的事情3..那么为什么1.不能编译呢?
虽然有许多类似的标题问题,但我无法清楚地将其识别为欺骗(除了错误信息相同),可能是因为我对Rust中的所有权/借用系统缺乏了解.
She*_*ter 10
在Rust中,编译器在评估泛型参数(包括通用生命周期参数)时停止在函数调用边界处.在你的情况1中,你正在调用一个方法:
fn get_qux(&mut self) -> &mut Qux {
&mut self.qux
}
Run Code Online (Sandbox Code Playgroud)
这个函数表明所有的self都是可变的,并且返回的引用将会生存self.在此期间,没有其他借用(可变或不可能)自我或其组成部分.
在你的第二种情况下,你构成了一个全新的Qux,它与你的结构无关.这不是一个非常好的例子,因为它具有非常不同的含义.如果这种情况适合你,你应该这样做.但是,您不会修改与案例1相同的内容.
在第三种情况下,您可以避免函数调用.这意味着编译器有更多关于确切借用的信息.具体来说,它可以看到self.qux根本不与之交互self.bars,因此没有错误.
您可以通过添加新范围来使原始示例工作:
fn run(&mut self) {
{
let mut qux = self.get_qux();
let qux_mut = &mut qux;
qux_mut.baz = true;
}
for bar in &self.bars {
println!("{:?}", bar);
}
}
Run Code Online (Sandbox Code Playgroud)
在这里,人工范围明确定义了可变借款的结束位置.借款结束后,其他项目可以进行新借款.
如果需要qux在循环内部进行修改,则需要遵循第三种模式:
let mut qux = &mut self.qux;
for bar in &self.bars {
qux.baz = ! qux.baz;
println!("{:?}", bar);
}
Run Code Online (Sandbox Code Playgroud)
或者更简单:
for bar in &self.bars {
self.qux.baz = ! self.qux.baz;
println!("{:?}", bar);
}
Run Code Online (Sandbox Code Playgroud)
很多时候,你可以重构代码来创建具有信息的新结构,并封装一个很好的变异边界来制作这样的代码.