Как добавить элемент в вектор и вернуть ссылку на этот элемент?

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

В функции add_child ниже я хочу добавить вновь созданный дочерний элемент в список дочерних элементов текущего элемента, а затем вернуть этот дочерний элемент, чтобы вызывающий объект мог, в свою очередь, добавить к этому дочернему элементу других дочерних элементов. Но я не могу, потому что потомок принадлежит вектору.

Каков «идиоматический» способ сделать подобные вещи в Rust?

Полагаю, я мог бы позволить потребителю моей библиотеки tag.rs самостоятельно манипулировать списком дочерних элементов в структуре, но тогда детали реализации не будут четко содержаться в функции.

Есть ли другой/лучший способ сделать это?

// tag.rs
use std::collections::HashMap;

pub struct Tag<'a> {
    name: &'a str,
    attributes: HashMap<&'a str, &'a str>,
    children: Vec<Tag<'a>>,
}

impl<'a> Tag<'a> {
    pub fn new(name: &'a str) -> Self {
        Self {
            name,
            attributes: HashMap::new(),
            children: vec![],
        }
    }

    pub fn add_child(&mut self, name: &'a str) -> Self {
        let mut child = Self::new(name);
        self.children.push(child); // `child` moved here
        child // <-- Error: use of moved value: `child`        
    }

    pub fn add_attribute(&mut self, key: &'a str, value: &'a str) {
        self.attributes.insert(key, value);
    }
}
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
0
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вы можете вернуть изменяемую ссылку на последний элемент:

pub fn add_child(&mut self, name: &'a str) -> &mut Self {
    let mut child = Self::new(name);
    self.children.push(child); // `child` moved here
    self.children.last_mut().unwrap()
}

Спасибо, это сработало! Но как компилятор позволяет это, не нарушая контракта владения? Я подумал, что, поскольку вектор теперь владеет ссылкой, вы не можете передать его изменяемую ссылку на другую функцию?

mydoghasworms 18.03.2024 06:49

@mydoghasworms, у вас есть изменяемая ссылка на дочерний элемент, что означает, что вы можете делать большинство вещей, кроме как удалить его. Это также означает, что вы не можете взаимодействовать с родителем, пока не перестанете использовать изменяемую ссылку.

drewtato 18.03.2024 07:24

@mydoghasworms вы не можете сохранить ссылку на оригинал, но после его перемещения вы можете получить ссылку через его владельца (vec), в этом смысл наличия первоклассных ссылок. Однако это ограничивает то, что вы можете делать с родителем (vec), поскольку у вас уже есть заем, чтобы добраться до дочернего элемента.

Masklinn 18.03.2024 08:39

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