我想制作一个具有安全接口的图形:
pub struct VertexId {
id: usize,
}
pub struct Graph {
vertices: Vec<String>,
edges: Vec<(VertexId, VertexId)>,
}
impl Graph {
pub fn add_vertex(&mut self, label: String) -> VertexId {
self.vertices.push(label);
VertexId { id: self.vertices.len() - 1 }
}
pub fn add_edge(&mut self, from: VertexId, to: VertexId) {
self.edges.push((from, to));
}
}
在这里,我创建了一个VertexId Package 器,以便您只能从Graph中获取顶点id。
但是,如果创建两个Graph,则可能使用无效的VertexId:
let mut a = Graph::new();
let vid = a.add_vertex("hello".to_string());
let mut b = Graph::new();
b.add_edge(vid, vid);
是否可以在编译时将vid
链接到a
?
1条答案
按热度按时间fdbelqdn1#
你可以使每个图示例成为一个自己的类型,一种方法是给它配备一个标识符,并要求顶点的标识符和图的标识符匹配。
例如,你可以执行this(我选择
IDENTIFIER
作为const u32
,但是你也可以使用一个类型):然后,每次构造一个图时,你都必须提供一个标识符,这很快就会变得很烦人,所以你可以定义这个帮助宏,它可以从行号中推断出标识符:
那么,你就不能将
add_edge
的顶点从a
转移到另一个图b
:注意,
make_graph
可能导致两个不同文件中的类型相同,但行号匹配。这也突出了它的一个缺点:一旦你把make_graph
移到另一行,你就会得到另一个类型。你可以通过使用类型作为标识符来解决这个问题,但是你必须一遍又一遍地声明标识符类型。**tl;dr;**仅仅因为可以在类型系统中强制执行某些内容,这并不一定是一个好主意。