我正在尝试在Rust中创建一个不相交的集合结构。看起来像这样
struct DisjointSet<'s> {
id: usize,
parent: &'s mut DisjointSet<'s>,
}
默认的不相交集是一个单例结构,父表示自身。因此,我希望可以选择执行以下操作:
let a: DisjointSet = DisjointSet {
id: id,
parent: self,
};
其中self
是对将要创建的对象的引用。
我尝试过创建自定义构造函数来解决这个问题。但是,我的尝试失败了,因为不允许部分初始化。编译器建议使用Option<DisjointSet<'s>>
,但这非常难看。你有什么建议吗?
我的问题与Structure containing fields that know each other不同 因为我有兴趣获得将要创建的结构的引用。
答案 0 :(得分:5)
正如@delnan所说,这些数据结构的核心是有向无环图(DAG),需要所有共享。 Rust对于共享可能发生的事情是严格的,所以在这种情况下说服编译器接受你的代码需要花费一些额外的努力。
幸运的是,&#34;所有共享需要&#34;字面上不是&#34;所有共享&#34;:DAG是非循环(模数希望有parent: self
),因此引用计数类型如{{1} }或Rc
是处理共享的完美方式(如果有循环,则引用计数不太好)。具体做法是:
Arc
对于这么小的类型,struct DisjointSet {
id: Cell<usize>,
parent: Rc<DisjointSet>,
}
的运行时开销为零(肯定会有一些句法开销)。
不幸的是,由于编译器建议使用Cell
的原因,这仍然不太正确。没有办法创建第一个Option<...>
。但是,建议的修复仍然有效:
DisjointSet
(struct DisjointSet {
id: Cell<usize>,
parent: Option<Rc<DisjointSet>>,
}
是免费的:Option<...>
是一个可以为空的指针,就像Option<Rc<...>>
是一个不可为空的指针一样,可能需要一个分支在&#34上;无论如何我是否有父母?#34;
如果您打算采用这种方法,我建议不要尝试使用Rc<...>
进行部分初始化,而是使用它来表示给定集合是&#34; root&#34的事实;。使用这种表示很容易遍历链,例如
Option
同样的方法应该适用于引用,但生命周期往往很难兼顾。