我试图在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()
}
}
}
}
我得到的错误是:
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
来避免这些错误,但是我无法更改每个集的父级,因为它们是不可变的 .
我读过类似的问题,例如:
-
Rust: "cannot move out of
self
because it is borrowed" error -
Can't borrow File from &mut self (error msg: cannot move out of borrowed content)
这些并没有帮助我解决如何解决这个问题 . 我也尝试重构函数 find
以及结构本身使用 Rc<RefCell<Set>>
和 Box<Set>
但我总是遇到同样的错误 .
这是什么错误,我该如何解决?
2 回答
这个匹配臂将按值获取枚举变量组件 . 由于您的类型不可复制,这意味着组件将移出原始位置 . 这会使你的原始结构部分未定义 - 在Rust中是一个很大的禁忌 .
要解决这个问题,请按照编译器的建议改为引用:
接下来,不是将结果存储在
Option
中,然后立即将其取出,尝试将引用保留在变量中,将其放入Option
并返回:这导致整个想法的核心问题:
您正在尝试存储可变引用并将其返回 . 这意味着将存在对同一项的多个并发可变引用(也称为别名) . 防止这是Rust的另一个核心原则 - 编译器更难以保证改变的时间和地点 .
查看this answer以查看一种解决方法 .
使用Option::take作为
match self.parent.take()
,这是这种情境中的基本习语 .self.parent.unwrap()
表达式也会导致错误;为此,你需要解决unwrap
消耗self
;您使用Option::as_mut来编写self.parent.as_mut().unwrap()
以使unwrap
使用引用 .最终的代码是: