不能借用 `self.x` 作为不可变的,因为 `*self` 也被借用为可变的 [英] cannot borrow `self.x` as immutable because `*self` is also borrowed as mutable

查看:23
本文介绍了不能借用 `self.x` 作为不可变的,因为 `*self` 也被借用为可变的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

首先让代码说话:

#[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();
}

这个错误:

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

如果我取消注释 2.3.,为什么它编译得很好?1. 中的被调用函数与 2.3. 没有什么明显不同.那么为什么 1. 无法编译?

If I uncomment either 2. or 3., why does it compile just fine? The called function in 1. doesn't do anything drastically different from 2. or 3.. So why is it then that 1. fails to compile?

尽管有许多类似标题的问题,但我无法清楚地将其识别为受骗(除了错误消息相同),可能是因为我对 Rust 中的所有权/借用系统缺乏了解.

Although there are many similar titled questions, I could not clearly identify this as a dupe (other than the error message being the same), possibly because of my lack of understanding of the ownership/borrowing system in Rust.

推荐答案

在 Rust 中,编译器在评估泛型参数(包括泛型生命周期参数)时会在函数调用边界处停止.在您的情况 1 中,您正在调用一个方法:

In Rust, the compiler stops at the function call boundary when evaluating generic parameters, which includes generic lifetime parameters. In your case 1, you are calling a method:

fn get_qux(&mut self) -> &mut Qux {
    &mut self.qux
}

这个函数表明selfall将被可变地借用,并且返回的引用将与self一样存在.在此期间,不得对 self 或其组件进行其他借用(无论是否可变).

This function indicates that all of self will be borrowed mutably, and that the returned reference will live as long as self will. During this time, no other borrows (mutable or not) of self or it's components may be made.

在您的第二种情况下,您创建了一个全新的 Qux,它与您的结构没有任何关联.这不是一个很好的例子,因为它具有非常不同的含义.如果这个案例适合你,你应该这样做.但是,您不会修改与案例 1 相同的内容.

In your second case, you make up a completely new Qux that has no attachment to your struct whatsoever. It's not a really great example, because it has very different meaning. If this case works for you, you should do that. However, you won't be modifying the same thing as case 1.

在第三种情况下,您避免了函数调用.这意味着编译器有更多关于究竟借用什么的信息.具体可以看到self.quxself.bars完全没有交互,所以没有报错.

In the third case, you avoid the function call. That means that the compiler has a bit more information about what exactly is borrowed. Specifically, it can see that self.qux doesn't interact at all with self.bars, so there is no error.

您可以通过添加新范围使原始示例工作:

You can make your original example work by adding a new scope:

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);
    }
}

在这里,人工作用域清楚地定义了可变借用的结束位置.借用结束后,允许其他项目再次借用.

Here, the artificial scope clearly defines where the mutable borrow ends. Once the borrow is over, other items are allowed to make new borrows.

如果需要在循环内部修改qux,则需要遵循第三种模式:

If you need to modify qux inside the loop, then you are required to follow the third pattern:

let mut qux = &mut self.qux;

for bar in &self.bars {
    qux.baz = ! qux.baz;
    println!("{:?}", bar);
}

或者更简单的:

for bar in &self.bars {
    self.qux.baz = ! self.qux.baz;
    println!("{:?}", bar);
}

很多时候,您可以重构您的代码以创建具有信息的新结构并封装一个很好的突变边界来制作这样的代码.

Many times, you can refactor your code to create new structs that have information and encapsulate a nice mutation boundary to make code like this.

这篇关于不能借用 `self.x` 作为不可变的,因为 `*self` 也被借用为可变的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆