为什么 Rust 的借用检查器在使用从方法返回的迭代器时会抱怨,而直接使用 Vec 的迭代器时却不会?

问题描述 投票:0回答:1

https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=ba9255e504174afa0f31f20467caf0a9

考虑以下 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 borrow-checker
1个回答
1
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.