Есть ли способ избежать использования RefCell в дереве, которое не будет видоизменяться после его создания? - PullRequest
0 голосов
/ 15 апреля 2019

Я пишу короткую программу для случайного создания подземелья для видеоигры , но у меня возникают некоторые проблемы с чистым созданием подземелий в дереве.

Что яИмеет уродливый и означает, что во время выполнения проверяется заимствование из-за 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 для такой ситуации, где они есть.

...