cannot borrow `*self` as mutable because it is also borrowed as immutable on returning an Option containing a reference to self

huangapple go评论79阅读模式
英文:

cannot borrow `*self` as mutable because it is also borrowed as immutable on returning an Option containing a reference to self

问题

这里,我有一个名为Bar的结构体,其中包含对Foo的引用。最近,我遇到了与此模式匹配的错误,并希望尝试创建一个可复现的示例。

struct Bar<'a> {
    foo: &'a Foo,
}

struct Foo;

impl Foo {
    fn borrow_mut(&mut self) {
        unimplemented!()
    }
    
    fn create_option_bar(&self) -> Option<Bar> { 
        unimplemented!() 
    }

    fn create_bar(&mut self) -> Bar {
        let option_bar = self.create_option_bar();
        if option_bar.is_some() {
            return option_bar.unwrap();
        }
        self.borrow_mut();
        unimplemented!()
    }
}

所以... 这个不会编译
但是,如果我像这样做一些事情

fn can_guarantee_option_bar_will_be_some() -> bool {
    unimplemented!()
}

impl Foo {
    // ... 与之前相同

    fn create_bar(&mut self) -> Bar {
        if can_guarantee_option_bar_will_be_some() {
            return self.create_option_bar().unwrap();
        }
        self.borrow_mut();
        unimplemented!()
    }
}

它可以工作!
现在... 这里到底发生了什么?这两者不是在做相同的事情吗?

我想知道

  • 为什么在第一个情况下不可能
  • 但在第二个情况下却是可能的
error[E0502]: 无法将`*self`同时借用为可变和不可变的原因
  --&gt; src/main.rs:44:9
   |
37 |     fn create_bar(&mut self) -> Bar {
   |                   - 让我们称这个引用的生命周期为`'1`
...
41 |         if let Some(bar) = self.create_option_bar() {
   |                            ------------------------ 在此处发生不可变借用
42 |             return bar;
   |                    --- 返回此值要求`*self`被借用为`'1`
43 |         }
44 |         self.borrow_mut();
   |         ^^^^^^^^^^^^^^^^^ 在此处发生可变借用

这是完整的错误消息。

英文:

Here, I have a struct Bar that has a reference to Foo in it. I recently got an error that matched this pattern and wanted to try and create a reproducible example.

struct Bar&lt;&#39;a&gt; {
    foo: &amp;&#39;a Foo,
}

struct Foo;

impl Foo {
    fn borrow_mut(&amp;mut self) {
        unimplemented!()
    }
    
    fn create_option_bar(&amp;self) -&gt; Option&lt;Bar&gt; { 
        unimplemented!() 
    }

    fn create_bar(&amp;mut self) -&gt; Bar {
        let option_bar = self.create_option_bar();
        if option_bar.is_some() {
            return option_bar.unwrap();
        }
        self.borrow_mut();
        unimplemented!()
    }
}

so... this doesn't compile
but, if i do something like this

fn can_guarantee_option_bar_will_be_some() -&gt; bool {
    unimplemented!()
}

impl Foo {
    // ... same as before

    fn create_bar(&amp;mut self) -&gt; Bar {
        if can_guarantee_option_bar_will_be_some() {
            return self.create_option_bar().unwrap();
        }
        self.borrow_mut();
        unimplemented!()
    }
}

it works fine!
now... what the heck is going on here? Aren't these both doing the same thing?

I want to know

  • why is this not possible in the first scenario
  • but is possible in the second
error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --&gt; src/main.rs:44:9
   |
37 |     fn create_bar(&amp;mut self) -&gt; Bar {
   |                   - let&#39;s call the lifetime of this reference `&#39;1`
...
41 |         if let Some(bar) = self.create_option_bar() {
   |                            ------------------------ immutable borrow occurs here
42 |             return bar;
   |                    --- returning this value requires that `*self` is borrowed for `&#39;1`
43 |         }
44 |         self.borrow_mut();
   |         ^^^^^^^^^^^^^^^^^ mutable borrow occurs here

here is the full error ^

答案1

得分: 1

您的代码使用了实验性的 Polonius 借用检查器:

RUSTFLAGS="-Zpolonius" cargo +nightly build

这是当前借用检查器的已知误报。有一个名为 polonius_the_crab 的 crate 可以解决这个问题。关于这个问题的更多信息可以在那里找到。

以下是使用这个 crate 修复它的方法:

use ::polonius_the_crab::prelude::*;

struct Bar<'a> {
    foo: &'a Foo,
}

struct Foo;

impl Foo {
    fn borrow_mut(&mut self) {
        unimplemented!()
    }

    fn create_option_bar(&self) -> Option<Bar> {
        unimplemented!()
    }

    fn create_bar(&mut self) -> Bar {
        let mut this = self;

        polonius!(|this| -> Bar<'polonius> {
            let option_bar = this.create_option_bar();
            if option_bar.is_some() {
                polonius_return!(option_bar.unwrap());
            }
        });

        this.borrow_mut();
        unimplemented!()
    }
}

除此之外,还有几种解决方法:

  • 在该 crate 的网站上有关于如何解决这个问题的好建议
  • 在项目中启用 Polonius(需要 Nightly 版本,不过仍然是实验性的)
  • 等待 Rust 将 Polonius 作为其主要借用检查器采用(可能需要一些时间,参见这里

很抱歉,目前没有直接的解决方案。

英文:

Your code builds with the experimental polonius borrow checker:

RUSTFLAGS=&quot;-Zpolonius&quot; cargo +nightly build

It is a known false positive of the current borrow checker. There's a crate to work around this issue, called polonius_the_crab. A lot more information about the problem can be found in there.

Here's how you would fix it using this crate:

use ::polonius_the_crab::prelude::*;

struct Bar&lt;&#39;a&gt; {
    foo: &amp;&#39;a Foo,
}

struct Foo;

impl Foo {
    fn borrow_mut(&amp;mut self) {
        unimplemented!()
    }

    fn create_option_bar(&amp;self) -&gt; Option&lt;Bar&gt; {
        unimplemented!()
    }

    fn create_bar(&amp;mut self) -&gt; Bar {
        let mut this = self;

        polonius!(|this| -&gt; Bar&lt;&#39;polonius&gt; {
            let option_bar = this.create_option_bar();
            if option_bar.is_some() {
                polonius_return!(option_bar.unwrap());
            }
        });

        this.borrow_mut();
        unimplemented!()
    }
}

Apart of that, there's several ways to solve this:

  • there's good advice on the crate's website on how to work around this issue
  • enable polonius in your project (requires nightly, though, and is still experimental)
  • wait until Rust adopts polonius as its primary borrow checker (might take a while, see here)

I'm sorry there isn't a straightforward solution to this.

huangapple
  • 本文由 发表于 2023年2月26日 23:59:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/75573210.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定