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

查看:124
本文介绍了不能借用不可变的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
}

此函数表示self all 将被可变借用,并且返回的引用将一直存在,只要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天全站免登陆