【问题标题】:How to avoid cloning parts when changing a mutable struct while recursion over that struct在递归结构时更改可变结构时如何避免克隆部分
【发布时间】:2021-11-08 21:40:16
【问题描述】:

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

如果没有 clone() rust 抱怨(正确地)我通过查看子节点和第二次在闭包中借用 self mutable。

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

此外,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)
    }
}

编辑:

  • Lagerbaer 建议使用 as_mut 但这会导致 current 成为 &mut 使用大小,这并不能真正解决问题。
  • 把孩子变成了孩子

【问题讨论】:

  • 你试过as_mut而不是.as_ref吗?
  • 这里的问题是它在一行中做的太多了。添加临时变量,一个正常的 for 循环,它更容易弄清楚。 clone() 的额外问题是您对节点的副本进行操作,并且无论您计算什么(我想如果您想改变它们,我想您将结果放入节点中)将在下一行被遗忘。你能完成代码示例吗?节点没有 calc_h,childs 类型似乎错误。

标签: recursion rust mutable borrow-checker


【解决方案1】:

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);
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-05
    • 2021-10-30
    相关资源
    最近更新 更多