有没有一种方法可以避免在创建后不会发生突变的树中使用RefCell?

时间:2019-04-15 18:09:20

标签: tree rust interior-mutability

我正在为randomly generate a video game dungeon写一个简短的程序,但是在树上干净地创建子地牢时遇到了一些麻烦。

我所拥有的是丑陋的,这意味着由于RefCell,运行时检查了借用,即使树在创建后不需要可变性。

由于它是一棵树,因此我使用了Rc<T>Weak<T>来分别保存对子节点和父节点的引用。这就产生了一个问题,因为子节点的值取决于其父节点的值,因此需要创建父节点以为其子节点提供父引用,而需要创建子节点以为其父节点提供子字段。

如果我使用一个在子节点之前创建子节点的函数(例如,通过在实例化父节点之前将子字段的相关值传递给它们),那么它们当然将无法获取对他们的父母。

唯一可行的方法是使用RefCell为每个节点创建子节点,如图所示。

这是每个节点的结构:

pub struct Dungeon {
    x: u32,
    y: u32,
    end_x: u32,
    end_y: u32,
    parent: Option<Weak<RefCell<Dungeon>>>,
    left: Option<Rc<RefCell<Dungeon>>>,
    right: Option<Rc<RefCell<Dungeon>>>,
}

这是给定根地牢的情况下用于生成树的功能的概述:

fn subdungeons(
    parent: Rc<RefCell<SubDungeon>>,
    level: u32,
) -> (Option<Rc<RefCell<Dungeon>>>, Option<Rc<RefCell<Dungeon>>>) {
    // These two lines are a stand-in for the actual code used to generate
    // the values for a child dungeon given its parent. The 'left'
    // and 'right' fields are necessarily 'None' after creation
    let mut left_sub: Dungeon = Dungeon::generate(Rc::downgrade(&parent));
    let mut right_sub: Dungeon = Dungeon::generate(Rc::downgrade(&parent));

    if level != 0 {
        let (l, r) = subdungeons(Rc::clone(&left_sub), level - 1);
        left_sub.borrow_mut().left = l;
        left_sub.borrow_mut().right = r;

        let (l, r) = subdungeons(Rc::clone(&right_sub), level - 1);
        right_sub.borrow_mut().left = l;
        right_sub.borrow_mut().right = r;
    }

    (Some(left_sub), Some(right_sub))
}

是否有一种不用引入RefCell的方式来重写它的方法?树在创建后不需要是可变的,但是我想不出任何其他方法来打破父级需要创建子级才能实例化的循环,但是子级也需要父级已经被创建。创建以获取其父母参考。

自然,在普通树中这不是问题,在普通树中,推送到父节点的节点的值通常与父节点的值无关,但是对于这种情况,我似乎找不到很好的Rust解决方案他们在哪里。

0 个答案:

没有答案