我有一个数据结构,可以表示为链接对象链接的一些结构之间的单向图,因为链接包含元数据。
它看起来像这样:
struct StateMachine {
resources: Vec<Resource>,
links: Vec<Link>,
}
struct Resource {
kind: ResourceType,
// ...
}
enum LinkTarget {
ResourceList(Vec<&Resource>),
LabelSelector(HashMap<String, String>),
}
struct Link {
from: LinkTarget,
to: LinkTarget,
metadata: SomeMetadataStruct,
}
整个结构需要是可变的,因为我需要能够在运行时添加和删除链接和资源。因此,我不能使用正常的生命周期模型并将资源绑定到父结构的生命周期。
我理解通过选择合适的类型我需要to "choose my own guarantee",但我不确定解决此问题的最佳方法是什么。
答案 0 :(得分:9)
实际上,对于类似图形的结构,最简单的解决方案是使用TypedArena
等竞技场。
节点的生命周期将仅取决于它们创建的类型化竞技场实例的生命周期,这将极大地简化资源管理。
警告:避免在图表中动态添加/删除节点的情况,因为在竞技场被删除之前,节点不会从竞技场中删除,因此竞技场的大小会增加,无限制。
如果您处于运行时添加/删除节点的情况,则另一种解决方案是:
defer
onload
(不是所有者,也不是借款人)两个例子:
Resources
Resources
,HashMap<ResourceId, (Resource, Vec<ResourceId>)>
和type R = RefCell<Resource>
在任何一种情况下,你都有责任在删除资源时清理边缘,忘记可能导致内存泄漏和恐慌(解除引用时),但在其他方面是安全的。
上面可能存在无限的变化。
答案 1 :(得分:9)
在Rust中建模类似图形的结构并不是一个简单的问题。 Nick Cameron和Niko Matsakis(Mozilla的两位主要Rust开发人员)进行了两次有价值的讨论。
答案 2 :(得分:5)
类似图形结构的最简单解决方案是使用模拟图形的库。 petgraph是一个不错的选择:
extern crate petgraph;
use std::rc::Rc;
use std::collections::HashMap;
use petgraph::Graph;
struct Resource;
enum LinkTarget {
ResourceList(Vec<Rc<Resource>>),
LabelSelector(HashMap<String, String>),
}
struct SomeMetadataStruct;
fn main() {
let mut graph = Graph::new();
let n1 = graph.add_node(LinkTarget::LabelSelector(Default::default()));
let n2 = graph.add_node(LinkTarget::LabelSelector(Default::default()));
let l2 = graph.add_edge(n1, n2, SomeMetadataStruct);
}
此处必须选择的保证以ResourceList
成员为中心。我假设您希望拥有单线程共享不可变Resource
s。
Vec<Arc<Resource>>
Vec<Resource>
Vec<Rc<RefCell<Resource>>>
(或Mutex
,如果也是多线程的)