考虑以下 Rust 程序
struct Foo {
bar: Vec<i32>,
baz: i32
}
impl Foo {
fn get_an_iter(&self) -> impl Iterator<Item=&i32> {
self.bar.iter()
}
fn do_mut_stuff_works(&mut self) {
for num in self.bar.iter() {
self.baz += num;
}
}
fn do_mut_stuff_does_not_work(&mut self) {
for num in self.get_an_iter() {
self.baz += num;
}
}
}
在
do_mut_stuff_works
中,我迭代向量 bar
并更改字段 baz
。为此,该方法需要采用 &mut self
。
现在,如果我将迭代器的创建从内联移动到方法
get_an_iter
,并尝试在do_mut_stuff_does_not_work
中迭代它,借用检查器会抱怨。
当使用
get_an_iter
时,不可变借用在整个循环中保持活动状态,这样我在 self.baz += num
处的可变借用就会失败,但是当我只是在方法内使用 for num in self.bar.iter()
创建迭代器时,借用是如何发生的?检查员高兴吗?
完整的编译器输出是:
Compiling playground v0.0.1 (/playground)
error[E0502]: cannot borrow `self.baz` as mutable because it is also borrowed as immutable
--> src/lib.rs:20:13
|
19 | for num in self.get_an_iter() {
| ------------------
| |
| immutable borrow occurs here
| immutable borrow later used here
20 | self.baz += num;
| ^^^^^^^^^^^^^^^ mutable borrow occurs here
For more information about this error, try `rustc --explain E0502`.
error: could not compile `playground` (lib) due to 1 previous error
Rust 可以在字段之间分割借用。在
do_mut_stuff_works
中,您从 self
的可变借用开始。当您使用 self.bar.iter()
时,该借用将被拆分:在 self.bar
循环期间,for
是不可改变地借用的。在此期间,self
的可变借用整体无效,但self.baz
的可变借用仍然存在。因此,您可以在体内增加self.baz
。
在
do_mut_stuff_does_not_work
中,您对整个 self
进行了不可变的借用,并将其交给 get_an_iter
,以便 self
的借用持续整个 for
循环。 Rust 不研究函数的定义来分割借用;这将泄漏签名中未包含的函数的实现细节。因此,即使get_an_iter
只需要不可变地借用self.bar
,do_mut_stuff_does_not_work
只知道它已经将整个self
一成不变地借给了get_an_iter
。因此,在循环体中不存在可以证明增加它的合理性的可变借用 self.baz
。