在&mut self方法中展开成员变量时,不能移出借用的内容

mcd*_*993 5 mutable ownership rust borrow-checker

我试图在Rust中创建一个Disjoint-Set数据结构。相关代码为:

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()
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我得到的错误是:

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()
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我不确定我是否完全了解借位检查器,但是我正在使用引用来避免自己获取结构体的所有权,以便可以像使用其他语言一样对它们进行指向和重新分配。

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

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

这些并不能帮助我解决该问题。我也尝试过重组函数find以及要使用的结构本身Rc<RefCell<Set>>Box<Set>但是我总是遇到相同的错误。

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

She*_*ter 4

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

要解决这个问题,请按照编译器的建议改为引用:

Some(ref mut p) =>
Run Code Online (Sandbox Code Playgroud)

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

let z = p.find();
self.parent = Some(z);
z
Run Code Online (Sandbox Code Playgroud)

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

Some(ref mut p) =>
Run Code Online (Sandbox Code Playgroud)

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

查看此答案以了解解决此问题的一种方法。