Tree 如何反序列化Rust中的引用树?

Tree 如何反序列化Rust中的引用树?,tree,rust,borrow-checker,Tree,Rust,Borrow Checker,我昨天开始使用Rust来实现今年的代码。挑战7让您解析文本文件中的树结构。输入如下所示: root->child1、child2 child1->child3 孩子2 孩子3 此格式表示从“根”开始的树;“root”有两个孩子(“child1”和“child2”),而“child1”有一个孩子(“child3”)。“child2”和“child3”没有孩子。该网站将永远不会向您发送有周期的输入 解析不是问题,但我在构建树结构时遇到了问题 如果这是C++,我会写这个: struct程序{ 字符串

我昨天开始使用Rust来实现今年的代码。挑战7让您解析文本文件中的树结构。输入如下所示:

root->child1、child2
child1->child3
孩子2
孩子3
此格式表示从“根”开始的树;“root”有两个孩子(“child1”和“child2”),而“child1”有一个孩子(“child3”)。“child2”和“child3”没有孩子。该网站将永远不会向您发送有周期的输入

解析不是问题,但我在构建树结构时遇到了问题

<>如果这是C++,我会写这个:

struct程序{
字符串名;
媒介儿童;
};
结构程序节点{
字符串&名称;
媒介儿童;
ProgramNode(字符串和名称);
};
向量程序=解析_程序();
无序的映射程序节点;
用于(程序和程序:程序){
program_nodes.emplace(program.name,ProgramNode(program.name));
}
用于(程序和程序:程序){
ProgramNode&node=program_nodes.at(program.name);
for(字符串和子项:program.children){
node.children.push_back(&program_nodes.at(child));
}
}
这将在第一步中构建“程序”的名称映射,并在第二步中填充对“子程序”的引用。如果您假定
程序映射
不会比
程序
更长寿,则这是安全的。然后,如果您知道根节点的名称,您可以在(root\u name)上执行
ProgramNode&root=program\u nodes.at并播放您的树

我试着用Rust写同样的东西,但我在借书检查上遇到了问题。到目前为止,我有一些类似的东西(没有有趣的细节
panic
'd): 使用std::collections::HashMap

struct Program {
    name: String,
    children: Vec<String>,
}

struct ProgramNode<'a> {
    name: &'a str,
    children: Vec<&'a ProgramNode<'a>>,
}

impl<'a> ProgramNode<'a> {
    fn new(input: &'a Program) -> ProgramNode {
        panic!();
    }
}

fn parse_programs() -> Vec<Program> {
    panic!();
}

fn main() {
    let programs = parse_programs();

    let mut program_nodes = HashMap::new();
    for program in &programs {
        program_nodes.insert(&program.name, ProgramNode::new(&program));
    }

    for program in &programs {
        let mut program_node = program_nodes.get_mut(&program.name).unwrap();
        for child in &program.children {
            program_node
                .children
                .push(&program_nodes.get_mut(&child).unwrap());
        }
    }
}

当然,借用检查器是绝对正确的。这就引出了一个问题:我试图做的一切可能吗?

使用拥有的值而不是不可变的引用来建模树更容易:节点拥有它的直接子节点。然而,由于问题7的目标是找到根节点,因此它可能不是最佳选择

解决冲突借用问题的主要解决方案是通过使用将借用检查推迟到运行时

使用std::cell::RefCell;
使用std::collections::HashMap;
结构程序{
名称:String,
儿童:Vec,
}
结构程序节点,
}
恳求{
fn new(输入:&'a Program)->programmanode{panic!();}
}
fn parse_programs()->Vec{panic!();}
fn main(){
让程序=解析_程序();
让mut program_nodes=HashMap::new();
用于程序中的程序(&P){
程序节点。插入(&program.name,ProgramNode::new(&program));
}
用于程序中的程序(&P){
让mut program_node=program_nodes.get(&program.name).unwrap();
适用于计划中的儿童&program.children{
program_node.children.borrow_mut().push(&program_nodes.get(&child.unwrap());
}
}
}

我发现在Rust中实现某些树状对象作为节点向量更容易

每个节点都有一个id,这是它在向量中的位置,该id用作指针

struct Node {
    parent: usize,
    children: Vec<usize>,
}
struct节点{
家长:使用,
儿童:Vec,
}
根通常位于位置0

无论何时通过将
节点推到树向量上创建
节点,树向量都会返回插入之前的长度,作为新
节点的id


如果还需要删除节点,则必须对实现进行一点改进。

关于同一问题的相关问题:。要清楚,我不会在查找根节点时陷入困境;我对每个节点名和每个子节点名进行了设置,并计算了差异以获得根(根是唯一不是其他任何节点的子节点)。如果有父指针,则不再有树,而是有一个图。使用索引的想法就是背后的设计。
struct Node {
    parent: usize,
    children: Vec<usize>,
}