代码之家  ›  专栏  ›  技术社区  ›  cadolphs

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

  •  0
  • cadolphs  · 技术社区  · 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_ter ,不可变的借位在整个循环中保持有效,因此我的可变借位在 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
    
    1 回复  |  直到 1 年前
        1
  •  2
  •   HTNW    1 年前

    铁锈罐 split borrows 在领域之间。在里面 do_mut_stuff_works ,你从一个可变的借用开始 self 。当你采取 self.bar.iter() ,借款被分割: self.bar 在的持续时间内不可更改地借用 for 环在此期间,的可变借用 自己 作为一个整体是无效的,但的可变借用 self.baz 残余因此,您可以增加 self.baz 体内。

    在里面 do_mut_stuff_does_not_work ,你向整个借了一笔不可变的钱 自己 并将其交给 get_an_iter ,因此借用 自己 持续整个 对于 环铁锈确实存在 探讨函数的定义以拆分借用;这将泄露签名中没有的函数的实现细节。所以即使 get_an_ter 只需要一个不可变的借用 self.bar , do_mut_stuff_doe_not_work 只知道它已经借出了全部 自己 ,不变地,到 get_an_ter 。因此,没有可变的借用 self.baz 在循环的主体中,这将证明递增它是合理的。