Data structures Rust vs Borrow Checker中的树遍历

Data structures Rust vs Borrow Checker中的树遍历,data-structures,rust,borrow-checker,Data Structures,Rust,Borrow Checker,我试图在Rust中实现一个树结构,遍历它,并修改它,但我在借用检查器方面遇到了麻烦。我的设置大致如下所示: #![feature(slicing_syntax)] use std::collections::HashMap; #[deriving(PartialEq, Eq, Hash)] struct Id { id: int, // let’s pretend it’s that } struct Node { children: HashMap<Id, Box

我试图在Rust中实现一个树结构,遍历它,并修改它,但我在借用检查器方面遇到了麻烦。我的设置大致如下所示:

#![feature(slicing_syntax)]

use std::collections::HashMap;

#[deriving(PartialEq, Eq, Hash)]
struct Id {
    id: int,  // let’s pretend it’s that
}

struct Node {
    children: HashMap<Id, Box<Node>>,
    decoration: String,
    // other fields
}

struct Tree {
   root: Box<Node>
}

impl Tree {
    /// Traverse the nodes along the specified path.
    /// Return the node at which traversal stops either because the path is exhausted
    /// or because there are no more nodes matching the path.
    /// Also return any remaining steps in the path that did not have matching nodes.
    fn traverse_path<'p>(&mut self, mut path: &'p [Id]) -> (&mut Box<Node>, &'p [Id]) {
        let mut node = &mut self.root;
        loop {
            match node.children.get_mut(&path[0]) {
                Some(child_node) => {
                    path = path[1..];
                    node = child_node;
                },
                None => {
                    break;
                }
            }
        }
        (node, path)
    }
}
struct PathIter<'a> {
    path: &'a [Id],
    node: &'a mut Box<Node>
}
impl<'a> Iterator<Box<Node>> for PathIter<'a> {
    fn next(&mut self) -> Option<Box<Node>> {
        let child = self.node.get_child(&self.path[0]);
        if child.is_some() {
            self.path = self.path[1..];
            self.node = child.unwrap();
        }
        child
    }
}
我理解为什么借阅检查器不喜欢此代码,但我不知道如何使其工作

我还尝试了使用迭代器的替代实现,代码如下:

#![feature(slicing_syntax)]

use std::collections::HashMap;

#[deriving(PartialEq, Eq, Hash)]
struct Id {
    id: int,  // let’s pretend it’s that
}

struct Node {
    children: HashMap<Id, Box<Node>>,
    decoration: String,
    // other fields
}

struct Tree {
   root: Box<Node>
}

impl Tree {
    /// Traverse the nodes along the specified path.
    /// Return the node at which traversal stops either because the path is exhausted
    /// or because there are no more nodes matching the path.
    /// Also return any remaining steps in the path that did not have matching nodes.
    fn traverse_path<'p>(&mut self, mut path: &'p [Id]) -> (&mut Box<Node>, &'p [Id]) {
        let mut node = &mut self.root;
        loop {
            match node.children.get_mut(&path[0]) {
                Some(child_node) => {
                    path = path[1..];
                    node = child_node;
                },
                None => {
                    break;
                }
            }
        }
        (node, path)
    }
}
struct PathIter<'a> {
    path: &'a [Id],
    node: &'a mut Box<Node>
}
impl<'a> Iterator<Box<Node>> for PathIter<'a> {
    fn next(&mut self) -> Option<Box<Node>> {
        let child = self.node.get_child(&self.path[0]);
        if child.is_some() {
            self.path = self.path[1..];
            self.node = child.unwrap();
        }
        child
    }
}
用于PathIter选项的结构PathIter迭代器 src/http\u prefix\u tree.rs:146 fn next(&mut self)->选项{ src/http_prefix_tree.rs:147 let child=self.node.get_child(&self.path[0]); src/http\u prefix\u tree.rs:148 if child.is\u some(){ src/http_prefix_tree.rs:149 self.path=self.path[1..]; src/http_prefix_tree.rs:150 self.node=child.unwrap(); src/http_prefix_tree.rs:151}
我感兴趣的另一件事是收集匹配节点的
装饰
字段的值,并在路径完全用尽时显示这些值。我最初的想法是从节点到它们的父节点建立反向链接,但我发现的唯一例子是
DList
中的
Rawlink
,这让我感到害怕我的下一个希望是迭代器实现(如果我能让它工作的话)这是你第一种方法的变体,使用递归避免借用冲突。迭代等价物无法编译,因为在处理可变借用值的可变借用指针时,Rust过于严格

impl Node {
    fn traverse_path<'p>(&mut self, mut path: &'p [Id]) -> (&mut Node, &'p [Id]) { // '
        if self.children.contains_key(&path[0]) {
            self.children[path[0]].traverse_path(path[1..])
        } else {
            (self, path)
        }
    }
}

impl Tree {
    /// Traverse the nodes along the specified path.
    /// Return the node at which traversal stops either because the path is exhausted
    /// or because there are no more nodes matching the path.
    /// Also return any remaining steps in the path that did not have matching nodes.
    fn traverse_path<'p>(&mut self, mut path: &'p [Id]) -> (&mut Node, &'p [Id]) { // '
        self.root.traverse_path(path)
    }
}
impl节点{
fn遍历路径(&mut节点,&p[Id]){/'
如果self.children.包含\u键(&路径[0]){
self.children[path[0]]。遍历路径(path[1..)
}否则{
(自我,路径)
}
}
}
impl树{
///沿指定路径遍历节点。
///返回遍历因路径耗尽而停止的节点
///或者因为没有更多的节点匹配路径。
///还返回路径中没有匹配节点的任何剩余步骤。
fn遍历路径(&mut节点,&p[Id]){/'
self.root.transverse\u路径(路径)
}
}
请注意,我已将返回类型从
&mut-Box
更改为
&mut-Node
;您不需要向用户透露您在实现中使用的是
。另外,请参见
节点::遍历路径
如何首先使用检查映射中是否有值,然后使用索引检索值。这意味着值被查找了两次,但这是我发现的唯一一种不需要不安全代码就可以工作的方法


附言:你可以将
树中的
更改为
节点
,而不是

你能发布错误吗?这会让事情变得更快。啊,严格的词法范围。只会在少数地方引起一系列恼人的问题,这类问题就是其中之一。顺便说一下,
&Box
>&mut-Box
是一件不好的事情;你应该处理
&mut-T
,例如,用
&mut*self.root
而不是
&mut-self.root
。这与
类似,但是想要返回
节点
意味着我无法说服编译器在没有
不安全的情况下接受它Morgan你能详细解释一下为什么提到盒子是一件坏事吗?这是一个风格问题,还是有更多的潜在危险?谢谢你的回答!也许有一种方法可以让迭代方法使用不安全的工具工作吗?