首页 > 解决方案 > 如何在递归更改可变结构时避免克隆部分

问题描述

我尝试递归地穿过一棵玫瑰树。以下代码也可以按预期工作,但由于借用检查器的问题,我仍然需要克隆值。因此,如果有办法从克隆变为更好的东西,那就太好了。

没有 clone() rust 抱怨(正确地)我通过查看子节点和闭包中的第二次来借用自我可变。

整个结构和代码比下面显示的更复杂和更大,但这是核心元素。我是否必须更改数据结构或者我错过了一些明显的东西?如果数据结构是问题,您将如何更改它?

此外,NType 枚举在这里似乎有点没用,但我还有一些其他类型需要考虑。这里内部节点总是有子节点,而外部节点永远不会。

enum NType{
    Inner,
    Outer
}

#[derive(Eq, PartialEq, Clone, Debug)]
struct Node {
    // isn't a i32 actually. In my real program it's another struct 
    count: i32,
    n_type: NType,
    children: Option<Vec<usize>>
}

#[derive(Eq, PartialEq, Clone, Debug)]
struct Tree {
    nodes: Vec<Node>,
}

impl Tree{
    
    pub fn calc(&mut self, features: &Vec<i32>) -> i32{
        // root is the last node
        self.calc_h(self.nodes.len() - 1, features);
        self.nodes[self.nodes.len() - 1].count.clone()
    }

    fn calc_h(&mut self, current: usize, features: &Vec<i32>){

        // do some other things to decide where to go into recursion and where not to
        // also use the features

        if self.nodes[current].n_type == Inner{
            //cloneing is very expensiv and destroys the performance
            self.nodes[current].children.as_ref().unwrap().clone().iter().for_each(|&n| self.calc_h(n, features));
            self.do_smt(current)
        }
        self.do_smt(current)
    }
}

编辑:

标签: recursionrustmutableborrow-checker

解决方案


child 的正确复数形式是children,所以这就是我将在此答案中提及的内容。大概这就是childs您的代码中的含义。

由于node.children已经是Option,因此最好的解决方案是.take()在迭代开始时将向量从节点中取出并在最后放入。这样我们就避免了tree.nodes在迭代期间持有对的引用。

if self.nodes[current].n_type == Inner {
    let children = self.nodes[current].children.take().unwrap();
    for &child in children.iter() {
        self.calc_h(child, features);
    }
    self.nodes[current].children = Some(children);
}

请注意,在循环的情况下,行为与原始代码不同,但如果树的其余部分正确实现,则无需担心。


推荐阅读