拥有的arena数据结构
Owned arena data structure
我想对由许多非常大(内存方面)的节点组成的非常大(节点数)的图建模。由于节点太大,我只想存储它们一次并向它们传递借用,所以从概念上讲是这样的:
struct Graph<'a> {
nodes: Vec<Node<'a>>,
}
struct Node<'a> {
edges: HashMap<String, &'a Node>,
// ...lots of other data...
}
当然没有办法像这样构造一个Graph
因为(a)Vec
不允许我在元素借用时添加新节点,并且(b)我不能告诉 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 表达吗?
一个简单的首选解决方案是使用 typed-arena 箱子。它包含一个 Arena
类型和一个 fn alloc(&self, T) -> &mut T
方法。
另一个简单的解决方案是使用索引而不是引用(永远不要从 Vec
中删除,因为这会使索引无效)。在 64 位平台上,使用 32 位索引可以减少一些字节。
但是,这两种解决方案都无法删除 节点。您可以停止引用它们,但它们仍将存在于内存中,因此将它们用于动态图(节点来来去去)需要更多的工作。在这种情况下,我的建议是定期从一个新的领域创建一个新的图形克隆(而不是复制未使用的节点),这类似于使用移动垃圾收集器,如果不那么自动的话。
我想对由许多非常大(内存方面)的节点组成的非常大(节点数)的图建模。由于节点太大,我只想存储它们一次并向它们传递借用,所以从概念上讲是这样的:
struct Graph<'a> {
nodes: Vec<Node<'a>>,
}
struct Node<'a> {
edges: HashMap<String, &'a Node>,
// ...lots of other data...
}
当然没有办法像这样构造一个Graph
因为(a)Vec
不允许我在元素借用时添加新节点,并且(b)我不能告诉 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 表达吗?
一个简单的首选解决方案是使用 typed-arena 箱子。它包含一个 Arena
类型和一个 fn alloc(&self, T) -> &mut T
方法。
另一个简单的解决方案是使用索引而不是引用(永远不要从 Vec
中删除,因为这会使索引无效)。在 64 位平台上,使用 32 位索引可以减少一些字节。
但是,这两种解决方案都无法删除 节点。您可以停止引用它们,但它们仍将存在于内存中,因此将它们用于动态图(节点来来去去)需要更多的工作。在这种情况下,我的建议是定期从一个新的领域创建一个新的图形克隆(而不是复制未使用的节点),这类似于使用移动垃圾收集器,如果不那么自动的话。