0ralo
@0ralo
Python backend developer

Как реализовать превращение вектора объектов в дерево?

Вопрос такой, что я делаю не так, мой алгоритм не работает, не понимаю.
У меня есть вектор объектов
#[derive(Default, Clone, Debug)]
struct Node {
    name: String,
    source: String,

    path: String,
    leaf: bool,
    children: Vec<RcNode>
}

Заполнены только name и source. name содержит имя, source - путь в дереве(A.B.C).
После исполнения функции должна остаться 1 нода, которая содержит в children ее детей, которые содержут своих детей и тд.
Я серьёзно застрял на 1 моменте - мне нужно создать ноду, запушить ее в вектор а потом использовать, чего раст мне конечно не даёт. В интернете нашел примеры использования Rc>, но не сумел получить необходимого эффекта. Если есть готовые решения, подсказки, ошибки или лучшие практики - буду рад узнать
Моя попытка (не рабочий вариант)
use std::cell::RefCell;
use std::rc::Rc;


#[derive(Default, Clone, Debug)]
struct Node {
    name: String,
    source: String,

    path: String,
    leaf: bool,
    children: Vec<RcNode>
}

type RcNode = Rc<RefCell<&'static Node>>;

impl Node {
    fn fast(name: &str, source: &str) -> Node{
        Node{
            name: name.to_string(),
            source: source.to_string(),

            path: String::from(""),
            leaf: true,
            children: Vec::new()
        }
    }

    fn insert(&'static self, node: Node){
        let mut current = Rc::new(RefCell::new(self));
        let mut temp;
        for part in node.source.split(".") {
            temp = node.children.iter().find(|&v| v.borrow().path == part);

            match temp {
                None => {
                    let tmp: RcNode = Rc::new(
                        RefCell::new(
                            &Node {
                                name: String::new(),
                                source: String::new(),

                                path: part.to_string(),
                                leaf: true,
                                children: Vec::new()
                            }
                        )
                    );
                    current.borrow_mut().children.push(
                        tmp
                    );
                    current = tmp;
                }
                Some(val) => {
                    current = val.clone()
                }
            }
        }
    }
}

fn main() {
    let mut root = Node::default();
    root.insert(Node::fast("First", "e"));
    root.insert(Node::fast("First", "e.sources"));
    root.insert(Node::fast("First", "e.sources.two"));
    root.insert(Node::fast("First", "e.secret"));
    root.insert(Node::fast("First", "e.secret.left"));
    root.insert(Node::fast("First", "e.secret.right"));
    print!("{:#?}", root);
}

Кстати объект имеет атрибут leaf, но как его реализовать я даже еще не дошел.
  • Вопрос задан
  • 70 просмотров
Решения вопроса 1
bingo347
@bingo347
Crazy on performance...
Главная проблема тут - лайфтаймы. В частности у переменной на стеке никогда не будет лайфтайма 'static.
Ну и отдавать в куда либо долгоживущее ссылку на временное значение - UB. Благо лайфтаймы и тут спасают.
Собственно для этого Rc и нужен - он владеющая ссылка. Соответственно в нём должно быть значение, а не ссылка (ссылка на ссылку редко когда нужна).

use std::cell::RefCell;
use std::rc::Rc;

#[derive(Default, Clone, Debug)]
struct NodeInner {
    name: String,
    source: String,

    path: String,
    leaf: bool,
    children: Vec<Node>,
}

#[derive(Default, Clone, Debug)]
struct Node(Rc<RefCell<NodeInner>>);

impl Node {
    fn fast(name: impl Into<String>, source: impl Into<String>) -> Self {
        Self(Rc::new(RefCell::new(NodeInner {
            name: name.into(),
            source: source.into(),

            path: String::new(),
            leaf: true,
            children: Vec::new(),
        })))
    }

    fn insert(&self, node: Node) {
        let mut current = self.clone();
        for part in node.0.borrow().source.split(".") {
            let inner = node.0.borrow();
            let found = inner.children.iter().find(|&v| v.0.borrow().path == part);

            match found {
                None => {
                    let tmp = Node::fast(String::new(), String::new());
                    current.0.borrow_mut().children.push(tmp.clone());
                    current = tmp;
                }
                Some(val) => current = val.clone(),
            }
        }
    }
}

fn main() {
    let mut root = Node::default();
    root.insert(Node::fast("First", "e"));
    root.insert(Node::fast("First", "e.sources"));
    root.insert(Node::fast("First", "e.sources.two"));
    root.insert(Node::fast("First", "e.secret"));
    root.insert(Node::fast("First", "e.secret.left"));
    root.insert(Node::fast("First", "e.secret.right"));
    print!("{:#?}", root);
}

Как заполнять поля уже сами разбирайтесь, думаю тут не сложно
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы