Я пробую свои силы в простом написании 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);
}
}
Вы можете вернуть изменяемую ссылку на последний элемент:
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, у вас есть изменяемая ссылка на дочерний элемент, что означает, что вы можете делать большинство вещей, кроме как удалить его. Это также означает, что вы не можете взаимодействовать с родителем, пока не перестанете использовать изменяемую ссылку.
@mydoghasworms вы не можете сохранить ссылку на оригинал, но после его перемещения вы можете получить ссылку через его владельца (vec), в этом смысл наличия первоклассных ссылок. Однако это ограничивает то, что вы можете делать с родителем (vec), поскольку у вас уже есть заем, чтобы добраться до дочернего элемента.
Спасибо, это сработало! Но как компилятор позволяет это, не нарушая контракта владения? Я подумал, что, поскольку вектор теперь владеет ссылкой, вы не можете передать его изменяемую ссылку на другую функцию?