我想模拟一个非常大(节点数)的图,该图包含许多非常大(内存方面)的节点。由于节点是如此之大,我想只存储一次并传递给它们,所以概念上是这样的:
struct Graph<'a> {
nodes: Vec<Node<'a>>,
}
struct Node<'a> {
edges: HashMap<String, &'a Node>,
// ...lots of other data...
}
当然没有办法像这样构造Graph
因为(a)Vec
不允许我在借用元素时添加新节点,并且(b)我可以& #39;告诉rustc nodes
向量将终生'a
。我也不能使用类似Rc
的内容,因为图表有周期。
我希望能够表达的是一个各种各样的竞技场,它让我分配了很多Node
,只要竞技场存在,就可以向他们借款,并使用终身检查来确保当竞技场被解除分配时,我没有剩余Node
个引用。类似的东西:
struct Graph<'a> {
nodes: Arena<'a, Node<'a>>,
}
struct Node<'a> {
edges: HashMap<String, &'a Node>,
}
impl<'a, A> Arena<'a, A> {
fn own(&self, a: A) -> &'a A {
// magic
}
}
impl<'a, A> Drop for Arena<'a, A> {
fn drop(&'a mut self) {
// magic
}
}
这在语义上是否可以在Rust中表达?
答案 0 :(得分:3)
一个简单的解决方案是使用typed-arena包。它包含Arena
类型和fn alloc(&self, T) -> &mut T
方法。
另一个简单的解决方案是使用索引而不是引用(并且永远不会从Vec
中删除,因为这会使索引无效)。在64位平台上,使用32位索引可以减少一些字节。
但是,这两种解决方案都无法删除节点。您可能会停止引用它们,但它们仍将存在于内存中,因此将它们用于动态图形(节点来去)需要更多的工作。我在这种情况下的建议是定期从一个新的竞技场创建一个新的图形克隆(不复制未使用的节点),这类似于使用移动垃圾收集器,如果不太自动。