结构中的可变载体

Mar*_* S. 2 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
Run Code Online (Sandbox Code Playgroud)

因此,邻接列表包含一个数组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;
    }
}
Run Code Online (Sandbox Code Playgroud)

但是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 });
                            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Run Code Online (Sandbox Code Playgroud)

那么,有两个主要问题:

1.我怎样才能使该add_edge方法起作用?

我认为WeightedGraph应该拥有所有内部数据(如果我错了,请纠正我).但为什么add_edge不能修改图表自己的数据呢?

2. ~Vec<~Vec<Edge>>表示在每个元素中保存动态列表的可变大小数组/列表的正确方法是什么?

该教程还提到~[int]了矢量语法,所以它应该是:~[~[Edge]]相反?或者Vec<Edge>和之间有什么区别~[Edge]?如果我应该使用~[~[Edge]],那么我将如何构建/初始化内部列表呢?(目前,我试图使用Vec::from_fn)

小智 7

WeightedGraph不拥有其所有内部数据,但即使你自己的东西,你必须选择加入变异它.get给你一个&指针,变异你需要一个&mut指针.Vec::get_mut会给你:self.adjacency_list.get_mut(source).push(...).

关于~Vec<Edge>~[Edge]:它曾经是(直到最近),其~[T]表示可增长的载体T,不像是写其他所有类型,~...这种特殊的情况下被删除,~[T]现在只是一个独特的指针T-slice,即一个拥有指针一堆T在没有任何增长能力的记忆中.Vec<T>现在是可增长的矢量类型.

需要注意的是它的Vec<T>,不是 ~Vec<T> ; 在~曾经是矢量语法的一部分,但在这里它只是一个普通的唯一指针,表示完全没有必要的间接和分配.你想要的adjacency_list: Vec<Vec<Edge>>.A Vec<T>是一个完全成熟的具体类型(data, length, capacity如果对您来说意味着什么,则为三元组),它封装了内存分配和间接,您可以将其用作值.你不会box因此获得任何收益,并且失去清晰度和表现.

你有另一个(次要的)问题:fn add_edge(mut self, ...)就像fn add_edge(self, ...)" self价值取值"一样.由于adjacency_list成员是线性类型(它可以是dropped,它是移动而不是隐式复制),因此您WeightedGraph也是线性类型.以下代码将失败,因为第一次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
Run Code Online (Sandbox Code Playgroud)

你想要&mut self:允许变异,self但不要取得它的所有权/不要移动它.

  • @MartinS.,是的,```只存在允许递归.[This](http://static.rust-lang.org/doc/master/guide-pointers.html)教程详细解释了指针.目前不能直接用作值的"非具体"类型是`[T]`和`T`,其中`T`是特征.也就是说,你不能使用没有指针的`[T]`和trait对象,因为它们的大小是未知的.这也在教程中解释. (2认同)