rust 无法将“*self”借用为可变的,因为在返回包含self引用的Option时,它也被借用为不可变的

gmxoilav  于 2023-03-02  发布在  其他
关注(0)|答案(1)|浏览(230)

在这里,我有一个结构体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 {
    // ... 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!()
    }
}

很好用!现在...这到底是怎么回事?这两个不是在做同样的事情吗?
我想知道

  • 为什么这在第一种情况下是不可能的
  • 但在第二种情况下 * 是 * 可能的
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

以下是完整的错误^

p8h8hvxi

p8h8hvxi1#

您的代码使用实验性的polonius borrow检查器构建:

RUSTFLAGS="-Zpolonius" cargo +nightly build

这是当前借位检查器的一个已知误报。有一个名为polonius_the_crab的板条箱可以解决这个问题。可以在那里找到关于这个问题的更多信息。
以下是使用此板条箱修复它的方法:

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(需要每晚,虽然,仍然是实验性的)
  • 等待,直到Rust采用polonius作为其主要借用检查器(可能需要一段时间,请参见here

我很抱歉没有一个简单的解决办法。

相关问题