结构中的可变载体

时间:2014-05-03 21:43:18

标签: graph rust

我正在尝试使用图形聚类算法在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数组数组:图中每个节点一个数组。内部数组包含该节点的邻居,表示为Edgetarget节点编号和双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}})

2 个答案:

答案 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)

  1. get仅返回不可变引用,如果要修改数据,则必须使用get_mut
  2. 你只需要Vec<Vec<Edge>>,Vec是正确的选择,~[]过去就是为了这个目的,但现在意味着其他东西(或者不确定是否已经改变了)< / LI>

    您还必须更改add_edge的签名以取消&mut self,因为现在您将self的所有权移至add_edge,这不是您想要的< / p>