单独链接列表,引用Rust中的随机节点

时间:2016-04-07 08:16:06

标签: rust

我正在尝试创建一个由节点组成的单链表,每个节点都有一个对下一个节点的引用,与该节点相关的数据,这是一个有趣的位,即对列表中随机节点的引用。给定节点的随机节点可以出现在节点本身之前,也可以出现在列表中。随机节点是可选的。这是一个图表:

       +---------+  +-------------------+
       |         v  v                   |
     +-+--+     ++--++     +----+     +-+--+
+--->+Data+---->+Data+---->+Data+---->+Data|
     +-+--+     +----+     +--+-+     +----+
       ^                      |
       +----------------------+

该图演示了一个包含四个节点的列表。第一节点的随机引用指向第二节点。缺少第二个节点的随机引用。第三个节点的随机引用是第一个节点。第四个节点的随机引用指向第二个节点。

该列表需要仅支持添加新节点。添加节点后,只要列表存在,就可以通过删除节点使随机引用失效。

我尝试了什么:

我陷入绝对的开端 - 我无法弄清楚如何设计结构以及如何构建列表。这是我在与编译器进行一段时间的摔跤之后得到的代码:

type NodePtr<'a, T> = Option<Box<Node<'a, T>>>;

pub struct Node<'a, T: 'a> {
    data: T,
    next: NodePtr<'a, T>,
    random: Option<&'a Node<'a, T>>,
}

pub struct List<'a, T: 'a> {
    root: NodePtr<'a, T>,
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn construct() {
        let mut list:List<i32> = List {root: Some(Box::new(Node {data: 5, next: None, random: None}))};
        let mut f: &mut Node<i32> = &mut **list.root.as_mut().unwrap();
        f.random = Some(&f);
    }
}

编译器拒绝使用以下命令编译它:

src/topology_copy.rs:21:26: 21:27 error: `f` does not live long enough
src/topology_copy.rs:21         f.random = Some(&f);

代码非常混乱。显然我做错了。

1 个答案:

答案 0 :(得分:5)

不幸的是,就编译器而言,您尝试实现的内容本质上是不安全的,因为您正在为可变节点创建别名。编译器会抱怨的两个可能的问题:

  • 没有证据表明该节点不会移动,因此您所引用的引用可能会失效
  • 没有证据表明该节点不会发生变异,因此有两个别名(并能够将两个别名交给它)会产生安全漏洞

现在是什么?

有各种方法。例如,如果您确定自己可以使用unsafe和原始指针。但是,更简单的解决方案是:

  • 使用Vec存储节点,使用索引链接它们
  • 使用RcWeak

前者是:

struct Node<T> {
    data: T,
    next: Option<usize>,
    random: Option<usize>,
}

pub struct List<T> {
    store: Vec<Node<T>>,
}

后者将是:

struct Node<T> {
    data: T,
    next: Option<Rc<Node<T>>,
    random: Option<Weak<Node<T>>,
}

pub struct List<T> {
    head: Option<Rc<Node<T>>,
}

后者不允许内部节点发生突变(因为存在固有的别名),因此您可能需要将T包装成RefCell<T>