【问题标题】:cannot move out of borrowed content when unwrapping a member variable in a &mut self method在 &mut self 方法中展开成员变量时无法移出借用的内容
【发布时间】:2015-03-27 11:25:16
【问题描述】:

我试图在 Rust 中创建一个不相交集数据结构。相关代码为:

pub struct Set<'a, T: 'a> {
    rank: u32,
    value: T,
    parent: Option<&'a mut Set<'a, T>>,
}

impl<'a, T> Set<'a, T> {
    pub fn find(&'a mut self) -> &'a mut Set<'a, T> {
        match self.parent {
            None => self,
            Some(mut p) => {
                self.parent = Some(p.find());
                self.parent.unwrap()
            }
        }
    }
}

我得到的错误是:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:9:15
   |
9  |         match self.parent {
   |               ^^^^ cannot move out of borrowed content
10 |             None => self,
11 |             Some(mut p) => {
   |                  ----- hint: to prevent move, use `ref p` or `ref mut p`

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:13:17
   |
13 |                 self.parent.unwrap()
   |                 ^^^^ cannot move out of borrowed content

我不确定我是否完全理解借用检查器,但我使用引用来避免获取结构本身的所有权,以便可以像使用其他语言一样指向和重新分配它们。

我可以通过从结构中的引用中删除 mut 来避免这些错误,但是我不能更改每个集合的父级,因为它们是不可变的。

我已经阅读了类似的问题,例如:

这些并不能帮助我解决这个问题。我也尝试过重构函数find 以及结构本身以使用Rc&lt;RefCell&lt;Set&gt;&gt;Box&lt;Set&gt;,但我总是以同样的错误告终。

这是什么错误,我该如何解决?

【问题讨论】:

  • 这是一个完全重复,因为这两个问题都与unwrap 消耗 Option这一事实有关。
  • @Shepmaster 我试过这样做,但后来我收到一个错误,告诉我我不能分配给 self.parent 因为它已经被借了。并且在第二个错误上使用as_mut() 使得我返回一个可变引用到一个似乎也不起作用的结构的可变引用。甚至试图将这个功能展开以逐步执行每个部分似乎都无法解决问题。
  • 您可能还对Hand-over-hand locking with Rust 感兴趣,其中有人也在尝试实施 union-find / disjoint-set。

标签: rust mutable ownership borrow-checker


【解决方案1】:

此匹配臂将按值获取枚举变量组件。由于您的类型不可复制,这意味着该组件将被移出原始位置。这将使您的原始结构部分未定义 - 在 Rust 中是一个很大的禁忌。

要解决这个问题,请参考编译器的建议:

Some(ref mut p) =>

接下来,不要将结果存储在 Option 中然后立即将其取出,而是尝试将引用保留在变量中,将其放入 Option 并返回:

let z = p.find();
self.parent = Some(z);
z

这导致了整个想法的核心问题:

error[E0499]: cannot borrow `*z` as mutable more than once at a time
  --> src/main.rs:14:17
   |
13 |                 self.parent = Some(z);
   |                                    - first mutable borrow occurs here
14 |                 z
   |                 ^ second mutable borrow occurs here
15 |             }
   |             - first borrow ends here

您正在尝试存储可变引用返回它。这将意味着对同一个项目有多个并发的可变引用(也称为别名)。防止这种情况发生是 Rust 安全系统的另一个核心原则,因为这样编译器就更难保证何时何地改变了。

查看this answer 了解解决此问题的一种方法。

【讨论】:

    【解决方案2】:

    Option::take 用作match self.parent.take(),这是这种情况下的基本习惯用法。

    self.parent.unwrap() 表达式也会导致错误;为此,您需要解决unwrap 消耗self 的事实;您使用 Option::as_mut 编写 self.parent.as_mut().unwrap()unwrap 使用引用。

    最终的代码是:

    pub struct Set<'a, T: 'a> {
        rank: u32,
        value: T,
        parent: Option<&'a mut Set<'a, T>>,
    }
    
    impl<'a, T> Set<'a, T> {
        pub fn find(&'a mut self) -> &'a mut Set<'a, T> {
            match self.parent.take() {
                None => self,
                Some(p) => {
                    self.parent = Some(p.find());
                    self.parent.as_mut().unwrap()
                }
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2015-03-18
      • 1970-01-01
      • 2017-08-10
      • 1970-01-01
      • 2018-04-04
      • 1970-01-01
      • 1970-01-01
      • 2015-04-20
      • 1970-01-01
      相关资源
      最近更新 更多