You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何直接用Vec迭代器无报错,调用方法返回的迭代器触发Rust借用检查错误?

Rust借用检查器:直接创建迭代器vs封装方法的差异

先看这段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方法里,直接遍历self.bar的迭代器并修改self.baz能正常编译;但把创建迭代器的逻辑封装到get_an_iter方法后,do_mut_stuff_does_not_work调用该方法遍历就会触发借用检查器报错。

编译错误信息如下:

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. 直接调用self.bar.iter()时,借用检查器能精准识别:迭代器仅借用了Foo的bar字段,属于单个字段的不可变借用。而修改self.baz是对另一个独立字段的可变借用,两者无重叠,符合Rust"不同字段的借用可共存"的规则。
  2. 调用get_an_iter(&self)时,方法签名里的&self表示对整个Foo实例的不可变借用。尽管方法内部只用到了bar字段,但借用检查器不会穿透方法调用分析内部实现——它只会依据签名判断:整个self已被不可变借用,此时再尝试可变借用self.baz,就违反了"同一实例不能同时存在可变与不可变借用"的规则。

解决方法

缩小方法的借用范围,只针对bar字段而非整个self即可:

struct Foo {
    bar: Vec<i32>,
    baz: i32
}

impl Foo {
    // 改为接收bar字段的引用,而非整个self
    fn get_an_iter(bar: &Vec<i32>) -> impl Iterator<Item=&i32> {
        bar.iter()    
    }
    
    fn do_mut_stuff_works(&mut self) {
        for num in self.bar.iter() {
            self.baz += num;
        }
    }
    
    fn do_mut_stuff_now_works(&mut self) {
        // 调用时传入bar字段的引用
        for num in Self::get_an_iter(&self.bar) {
            self.baz += num;
        }
    }
}

修改后,借用检查器能识别迭代器仅借用bar字段,修改baz是独立的可变借用,两者可共存,编译即可通过。

内容的提问来源于stack exchange,提问作者cadolphs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 20:07:45