Data structures 如何以安全的方式表示相互递归的数据结构?

Data structures 如何以安全的方式表示相互递归的数据结构?,data-structures,rust,Data Structures,Rust,我正在尝试在Rust中实现一个类似场景图的数据结构。我想一个等价于这个C++代码的安全锈:< /p> struct节点 { Node*parent;//应该是可变的,并且可以为null(没有父节点) 性病:病媒儿童; 虚拟节点() { for(auto it=child.begin();it!=child.end();+it) { 删除*它; } } void addNode(节点*新节点) { 如果(新节点->父节点) { newNode->parent.child.erase(newNod

我正在尝试在Rust中实现一个类似场景图的数据结构。我想一个等价于这个C++代码的安全锈:< /p>
struct节点
{
Node*parent;//应该是可变的,并且可以为null(没有父节点)
性病:病媒儿童;
虚拟节点()
{ 
for(auto it=child.begin();it!=child.end();+it)
{
删除*它;
}
}
void addNode(节点*新节点)
{
如果(新节点->父节点)
{
newNode->parent.child.erase(newNode->parent.child.find(newNode));
}
newNode->parent=this;
child.push_back(newNode);
}
}
我想要的财产:

  • 父母拥有孩子的所有权
  • 节点可以通过某种引用从外部访问
  • 触及一个
    节点的事件可能会改变整个树

问题在于这种数据结构本身就不安全;它没有一种不使用
不安全
的直接等效防锈剂。这是故意的

如果你想把它翻译成安全的防锈代码,你需要更具体地说明你到底想从中得到什么。我知道你在上面列出了一些属性,但是经常有人会说“我想要这个C/C++代码中的所有东西”,而直接的答案是“嗯,你不能。”

你也不可避免地要改变你的方法。您给出的示例中的指针没有任何所有权语义、可变别名和循环;所有的锈蚀都不能让你像C++那样简单地忽略。

最简单的解决方案是去掉
父指针
并在外部维护它(如文件系统路径)。这对借款也很好,因为任何地方都没有周期:

pub struct Node1 {
    children: Vec<Node1>,
}
在这里,您可以使用
Node3
在树的各个部分之间转移节点的所有权,使用
WeakNode3
进行外部引用。或者,您可以使
Node3
可克隆,并在
add
中添加回逻辑,以确保给定节点不会意外地成为错误父节点的子节点

严格来说,这并不比第二个选项好,因为此设计绝对不能从静态借用检查中获益。第二种方法至少可以防止您在编译时同时从两个位置对图形进行变异;在这里,如果发生这种情况,你就会崩溃


关键是:你不能什么都有。您必须决定实际需要支持哪些操作。在这一点上,通常只需要选择提供必要属性的类型。

Rust通过禁止您执行可能不安全的操作来确保内存安全。由于此分析是在编译时执行的,编译器只能对已知安全的操作子集进行推理

在Rust中,您可以轻松地存储对父节点的引用(通过借用父节点,从而防止突变)或子节点列表(通过拥有它们,这给了您更多的自由),但不能同时存储两者(不使用
不安全的
)。这对于
addNode
的实现尤其有问题,因为它需要对给定节点的父节点进行可变访问。但是,如果将
父节点
指针存储为可变引用,那么,由于一次只能使用对特定对象的单个可变引用,因此访问父节点的唯一方法是通过子节点,并且只能使用单个子节点,否则,将有两个对同一父节点的可变引用

如果你想避免不安全的代码,有很多选择,但它们都需要一些牺牲


最简单的解决方案是简单地删除
父项
字段。我们可以定义一个单独的数据结构,以便在遍历树时记住节点的父节点,而不是将其存储在节点本身中

首先,让我们定义
节点

#[derive(Debug)]
struct Node<T> {
    data: T,
    children: Vec<Node<T>>,
}

impl<T> Node<T> {
    fn new(data: T) -> Node<T> {
        Node { data: data, children: vec![] }
    }

    fn add_child(&mut self, child: Node<T>) {
        self.children.push(child);
    }
}
如果您不需要在导航树时对其进行变异,并且可以保留父级
NavigableNode
对象(这对于递归算法很好,但如果您希望将
NavigableNode
存储在其他一些数据结构中并保留它,则此解决方案效果不太好)。第二个限制可以通过使用借来的指针以外的东西来存储父对象来减轻;如果希望最大通用性,可以使用允许直接值、借用的指针、
es、
Rc


现在,让我们谈谈。在函数式编程中,拉链用于“聚焦”数据结构的特定元素(列表、树、地图等),因此访问该元素需要固定的时间,同时仍保留该数据结构的所有数据。如果您需要在导航期间导航树并对其进行变异,同时保留向上导航树的能力,则可以将树变成拉链,并通过拉链执行修改

下面是我们如何为上面定义的
节点实现拉链:

#[derive(Debug)]
struct NodeZipper<T> {
    node: Node<T>,
    parent: Option<Box<NodeZipper<T>>>,
    index_in_parent: usize,
}

impl<T> NodeZipper<T> {
    fn child(mut self, index: usize) -> NodeZipper<T> {
        // Remove the specified child from the node's children.
        // A NodeZipper shouldn't let its users inspect its parent,
        // since we mutate the parents
        // to move the focused nodes out of their list of children.
        // We use swap_remove() for efficiency.
        let child = self.node.children.swap_remove(index);

        // Return a new NodeZipper focused on the specified child.
        NodeZipper {
            node: child,
            parent: Some(Box::new(self)),
            index_in_parent: index,
        }
    }

    fn parent(self) -> NodeZipper<T> {
        // Destructure this NodeZipper
        let NodeZipper { node, parent, index_in_parent } = self;

        // Destructure the parent NodeZipper
        let NodeZipper {
            node: mut parent_node,
            parent: parent_parent,
            index_in_parent: parent_index_in_parent,
        } = *parent.unwrap();

        // Insert the node of this NodeZipper back in its parent.
        // Since we used swap_remove() to remove the child,
        // we need to do the opposite of that.
        parent_node.children.push(node);
        let len = parent_node.children.len();
        parent_node.children.swap(index_in_parent, len - 1);

        // Return a new NodeZipper focused on the parent.
        NodeZipper {
            node: parent_node,
            parent: parent_parent,
            index_in_parent: parent_index_in_parent,
        }
    }

    fn finish(mut self) -> Node<T> {
        while let Some(_) = self.parent {
            self = self.parent();
        }

        self.node
    }
}

impl<T> Node<T> {
    fn zipper(self) -> NodeZipper<T> {
        NodeZipper { node: self, parent: None, index_in_parent: 0 }
    }
}
#[派生(调试)]
结构NodeZipper{
节点:节点,
家长:选择,
父项中的索引:usize,
}
impl NodeZipper{
fn子项(多个自我,索引:usize)->NodeZipper{
//从节点的子节点中删除指定的子节点。
//NodeZipper不应该让用户检查其父节点,
//因为我们变异了父母
//将聚焦节点从其子节点列表中移出。
//为了提高效率,我们使用swap_remove()。
让child=self.node.children.swap\u删除(索引);
//返回聚焦于指定子级的新NodeZipper。
诺德齐珀{
节点:子节点,
父项:某些(框::新(自身)),
父项中的索引:索引,
}
#[derive(Debug)]
struct Node<T> {
    data: T,
    children: Vec<Node<T>>,
}

impl<T> Node<T> {
    fn new(data: T) -> Node<T> {
        Node { data: data, children: vec![] }
    }

    fn add_child(&mut self, child: Node<T>) {
        self.children.push(child);
    }
}
#[derive(Debug)]
struct NavigableNode<'a, T: 'a> {
    node: &'a Node<T>,
    parent: Option<&'a NavigableNode<'a, T>>,
}

impl<'a, T> NavigableNode<'a, T> {
    fn child(&self, index: usize) -> NavigableNode<T> {
        NavigableNode {
            node: &self.node.children[index],
            parent: Some(self)
        }
    }
}

impl<T> Node<T> {
    fn navigate<'a>(&'a self) -> NavigableNode<T> {
        NavigableNode { node: self, parent: None }
    }
}
#[derive(Debug)]
struct NodeZipper<T> {
    node: Node<T>,
    parent: Option<Box<NodeZipper<T>>>,
    index_in_parent: usize,
}

impl<T> NodeZipper<T> {
    fn child(mut self, index: usize) -> NodeZipper<T> {
        // Remove the specified child from the node's children.
        // A NodeZipper shouldn't let its users inspect its parent,
        // since we mutate the parents
        // to move the focused nodes out of their list of children.
        // We use swap_remove() for efficiency.
        let child = self.node.children.swap_remove(index);

        // Return a new NodeZipper focused on the specified child.
        NodeZipper {
            node: child,
            parent: Some(Box::new(self)),
            index_in_parent: index,
        }
    }

    fn parent(self) -> NodeZipper<T> {
        // Destructure this NodeZipper
        let NodeZipper { node, parent, index_in_parent } = self;

        // Destructure the parent NodeZipper
        let NodeZipper {
            node: mut parent_node,
            parent: parent_parent,
            index_in_parent: parent_index_in_parent,
        } = *parent.unwrap();

        // Insert the node of this NodeZipper back in its parent.
        // Since we used swap_remove() to remove the child,
        // we need to do the opposite of that.
        parent_node.children.push(node);
        let len = parent_node.children.len();
        parent_node.children.swap(index_in_parent, len - 1);

        // Return a new NodeZipper focused on the parent.
        NodeZipper {
            node: parent_node,
            parent: parent_parent,
            index_in_parent: parent_index_in_parent,
        }
    }

    fn finish(mut self) -> Node<T> {
        while let Some(_) = self.parent {
            self = self.parent();
        }

        self.node
    }
}

impl<T> Node<T> {
    fn zipper(self) -> NodeZipper<T> {
        NodeZipper { node: self, parent: None, index_in_parent: 0 }
    }
}
use std::{
    cell::{Cell, RefCell},
    fmt,
};
use typed_arena::Arena; // 1.6.1

struct Tree<'a, T: 'a> {
    nodes: Arena<Node<'a, T>>,
}

impl<'a, T> Tree<'a, T> {
    fn new() -> Tree<'a, T> {
        Self {
            nodes: Arena::new(),
        }
    }

    fn new_node(&'a self, data: T) -> &'a mut Node<'a, T> {
        self.nodes.alloc(Node {
            data,
            tree: self,
            parent: Cell::new(None),
            children: RefCell::new(Vec::new()),
        })
    }
}

struct Node<'a, T: 'a> {
    data: T,
    tree: &'a Tree<'a, T>,
    parent: Cell<Option<&'a Node<'a, T>>>,
    children: RefCell<Vec<&'a Node<'a, T>>>,
}

impl<'a, T> Node<'a, T> {
    fn add_node(&'a self, data: T) -> &'a Node<'a, T> {
        let child = self.tree.new_node(data);
        child.parent.set(Some(self));
        self.children.borrow_mut().push(child);
        child
    }
}

impl<'a, T> fmt::Debug for Node<'a, T>
where
    T: fmt::Debug,
{
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{:?}", self.data)?;
        write!(f, " (")?;
        for c in self.children.borrow().iter() {
            write!(f, "{:?}, ", c)?;
        }
        write!(f, ")")
    }
}

fn main() {
    let tree = Tree::new();
    let head = tree.new_node(1);
    let _left = head.add_node(2);
    let _right = head.add_node(3);

    println!("{:?}", head); // 1 (2 (), 3 (), )
}