英文:
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`同时借用为可变和不可变的原因
--> 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<'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!()
}
}
so... this doesn't compile
but, if i do something like this
fn can_guarantee_option_bar_will_be_some() -> bool {
unimplemented!()
}
impl Foo {
// ... same as before
fn create_bar(&mut self) -> 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
--> src/main.rs:44:9
|
37 | fn create_bar(&mut self) -> Bar {
| - let's call the lifetime of this reference `'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 `'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="-Zpolonius" 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<'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!()
}
}
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论