我正在尝试使用图形聚类算法在Rust中工作。部分代码是WeightedGraph
数据结构,具有邻接列表表示。核心将像这样表示(在Python中显示,以明确我正在尝试做什么):
class Edge(object):
def __init__(self, target, weight):
self.target = target
self.weight = weight
class WeightedGraph(object):
def __init__(self, initial_size):
self.adjacency_list = [[] for i in range(initial_size)]
self.size = initial_size
self.edge_count = 0
def add_edge(self, source, target, weight):
self.adjacency_list[source].append(Edge(target, weight))
self.edge_count += 1
因此,邻接列表包含一个n
数组数组:图中每个节点一个数组。内部数组包含该节点的邻居,表示为Edge
(target
节点编号和双weight
)。
我将整个事情翻译成Rust的尝试看起来像这样:
struct Edge {
target: uint,
weight: f64
}
struct WeightedGraph {
adjacency_list: ~Vec<~Vec<Edge>>,
size: uint,
edge_count: int
}
impl WeightedGraph {
fn new(num_nodes: uint) -> WeightedGraph {
let mut adjacency_list: ~Vec<~Vec<Edge>> = box Vec::from_fn(num_nodes, |idx| box Vec::new());
WeightedGraph {
adjacency_list: adjacency_list,
size: num_nodes,
edge_count: 0
}
}
fn add_edge(mut self, source: uint, target: uint, weight: f64) {
self.adjacency_list.get(source).push(Edge { target: target, weight: weight });
self.edge_count += 1;
}
}
但是rustc给了我这个错误:
weightedgraph.rs:24:9: 24:40 error: cannot borrow immutable dereference of `~`-pointer as mutable
weightedgraph.rs:24 self.adjacency_list.get(source).push(Edge { target: target, weight: weight });
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
所以,有两个主要问题:
1。如何使add_edge
方法起作用?
我认为WeightedGraph应该拥有所有内部数据(如果我错了,请纠正我)。但是为什么add_edge
不能修改图表自己的数据?
2。 ~Vec<~Vec<Edge>>
是表示在每个元素中保存动态列表的可变大小数组/列表的正确方法吗?
本教程还提到了~[int]
作为矢量语法,所以它应该是:~[~[Edge]]
而不是?Vec<Edge>
?或者~[Edge]
和~[~[Edge]]
之间有什么区别?如果我应该使用Vec::from_fn
,那么我将如何构建/初始化内部列表呢? (目前,我尝试使用{{1}})
答案 0 :(得分:7)
WeightedGraph
确实拥有所有内部数据,但即使您拥有某些东西,也必须选择改变它。 get
给你一个&
指针,要改变你需要一个&mut
指针。 Vec::get_mut
将为您提供:self.adjacency_list.get_mut(source).push(...)
。
关于~Vec<Edge>
和~[Edge]
:过去(直到最近)~[T]
表示T
的可增长向量,与其他类型的~...
不同。 s written ~[T]
此特例已被删除,T
现在只是指向T
- 切片的唯一指针,即指向内存中一堆Vec<T>
的拥有指针没有任何增长能力。 Vec<T>
现在是可增长的矢量类型。
请注意,它是~Vec<T>
,不是 ~
; adjacency_list: Vec<Vec<Edge>>
曾经是矢量语法的一部分,但在这里它只是一个普通的唯一指针,代表了完全不必要的间接和分配。你想要Vec<T>
。 data, length, capacity
是一个完全成熟的具体类型(三box
,如果这对您来说意味着什么),它封装了内存分配和间接,您可以将它用作值。你fn add_edge(mut self, ...)
没有获得任何好处,也失去了清晰度和表现。
您还有另一个(次要)问题:fn add_edge(self, ...)
,如self
,意味着&#34;按值adjacency_list
和#34;。由于drop
成员是线性类型(它可以是WeightedGraph
ped,它被移动而不是隐式复制),您的add_edge
也是线性类型。以下代码将失败,因为第一个let g = WeightedGraph::new(2);
g.add_edge(1, 0, 2); // moving out of g
g.add_edge(0, 1, 3); // error: use of g after move
调用消耗了图表。
&mut self
您想要self
:允许{{1}}变异,但不要取得它的所有权/不要移动它。
答案 1 :(得分:2)
get
仅返回不可变引用,如果要修改数据,则必须使用get_mut
Vec<Vec<Edge>>
,Vec是正确的选择,~[]
过去就是为了这个目的,但现在意味着其他东西(或者不确定是否已经改变了)< / LI>
醇>
您还必须更改add_edge
的签名以取消&mut self
,因为现在您将self
的所有权移至add_edge
,这不是您想要的< / p>