Пример дерева вопросов для обучения Rust. Обновить элемент внутри Rc

Я изучаю ржавчину и застрял на вопросе о Rc, Weak и RefCell. Вариант использования — реализовать полностью функционирующее дерево, в котором каждый узел имеет одного родителя и список дочерних элементов. Документация обеспечивает хорошую отправную точку:

use std::cell::RefCell;
use std::rc::{Rc, Weak};

#[derive(Debug)]
struct Node {
    value: i32,
    parent: RefCell<Weak<Node>>,
    children: RefCell<Vec<Rc<Node>>>,
}

fn main() {
    let leaf = Rc::new(Node {
        value: 3,
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(vec![]),
    });

    println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());

    let branch = Rc::new(Node {
        value: 5,
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(vec![Rc::clone(&leaf)]),
    });

    *leaf.parent.borrow_mut() = Rc::downgrade(&branch);

    println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
}

Но. Когда я пытаюсь расширить это, возникает проблема с дизайном. Я не могу добавить новый узел к уже состоящему. У узла branch есть дочерний узел, но я думаю, что это возможно только потому, что мы уже знаем, что leaf будет единственным дочерним элементом, прежде чем будет создан branch. Если это не так, можем ли мы как-то изменить branch после того, как он уже был создан внутри Rc, и добавить leaf в качестве дочернего?

Или я должен оставить этот дизайн и принять дизайн, который больше похож на:

#[derive(Debug)]
struct Node {
    value: i32,
    parent: Weak<RefCell<Node>>,
    children: Vec<Rc<RefCell<Node>>>,
}
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
0
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы можете добавить новые листья с помощью следующего кода:

let new_leaf = Rc::new(Node {
    value: 4,
    parent: RefCell::new(Rc::downgrade(&branch)),
    children: RefCell::new(vec![])
});

branch.children.borrow_mut().push(new_leaf);

При этом предложенный вами альтернативный тип Node, похоже, является тем, с чем большинство rustaceans пошли бы / с которыми более знакомы.

Очевидно, я недостаточно хорошо понимаю Rc. Получается, вы можете видоизменять объект внутри Rc, пока один из его элементов обернут RefCell? Я знал, что это можно сделать с помощью прямого Rc<RefCell<SomeType>>, но не с помощью Rc<SomeType{ RefCell < SomeMemberType > } >. Спасибо.

hasdrubal 14.11.2022 15:38

В том-то и дело, что RefCell он позволяет изменять свое содержимое и требует для этого только общую ссылку, как вы можете видеть в подписи fn borrow_mut(&self) -> RefMut<'_, T>, где RefMut<'_, T> по сути является изменяемой ссылкой &mut T плюс подсчет ссылок во время выполнения.

cafce25 14.11.2022 16:03

Другие вопросы по теме