首页 > 解决方案 > Rust - 使用子节点的输出更新树节点

问题描述

我正在尝试实现一个结构,其中每个节点都使用其节点的一些输出进行更新

在最终应用程序中不能克隆或移动输出。当我为其子节点提供节点引用来更新它时,我遇到了多个借用错误。

我正在使用indextree板条箱。

无法理解它......无法通过这种更新行为找到类似的东西。

我的示例代码

树包含这样的动态节点

type NodeOutput = i64; //(Can't be copied) wgpu::TextureView in final version  

trait CalcNode {
    fn update(&mut self, input: Vec<&dyn CalcNode>);
    fn output(&self) -> NodeOutput;
}
 
struct NodeModel {
    output: NodeOutput, // generated output ()
    internal: i64,      // some internal state
}
 
impl CalcNode for NodeModel {
    //input can't be cloned/copied in final version
    fn update(&mut self, input: Vec<&dyn CalcNode>) {
        //example for a possible update function
        let child_input: i64 = input.iter().map(|&f| f.output()).sum();
        self.output = self.internal * child_input;
        self.internal += 1 
        // this is only an simplified example 
        //the final version is rendering to a Texture
    }
 
    fn output(&self) -> NodeOutput {
        // output is not copy-able in final version
        self.output
    }
}
 
impl NodeModel {
    fn new(internal: i64) -> Self {
        Self {
            output: internal,
            internal,
        }
    }
}

然后我试图像这样更新树:

use indextree::{Arena, NodeId};

fn main() {
    let (mut arena_, root) = build_tree(); //generate some Tree
    let arena = &mut arena_;
 

    let node_stack: Vec<NodeId> = root.descendants(arena).collect(); //collect all nodes depth first
 

        //update in reverse order deepest node first, ROOT LAST.
        for &n in node_stack.iter().rev() {

            // collect updated children when available
            let children: Vec<&dyn CalcNode> = {
                n.children(arena)
                    .map(|f| arena.get(f).unwrap().get().as_ref())
                    .collect()
            };
 
            //get the node to update
            //--- can't borrow arena here to get the node ---
            let node = { arena.get_mut(n).unwrap().get_mut().as_mut() }; 
 
            // update the node
            node.update(children);
        }
    
}

标签: dynamicrusttreeborrow-checker

解决方案


CalcNode::update函数实际上不需要访问其子级 - 实际上它只需要从它们计算的值,因此您可以将计算移出update函数以防止别名引用:

fn update(&mut self, child_input: i64) {
    self.output = self.internal * child_input;
    self.internal += 1
}
// <-- Main loop
for &n in node_stack.iter().rev() {
    // collect updated children when available
    let children: Vec<&dyn CalcNode> = {
        n.children(arena)
            .map(|f| arena.get(f).unwrap().get().as_ref())
            .collect()
    };
    //example for n possible update funciton
    let child_input: i64 = children.iter().map(|&f| f.output()).sum();

    //get the node to update
    let node = { arena.get_mut(n).unwrap().get_mut().as_mut() };
    node.update(child_input);
}

推荐阅读