У меня есть древовидная структура, подобная следующей:
use std::{cell::RefCell, collections::HashMap, rc::Rc};
struct Node<T> {
vals: HashMap<String, T>,
parent: Option<Rc<RefCell<Node<T>>>>,
}
Это сцепленная хеш-карта: каждый узел содержит хеш-карту и (необязательно, так как корень дерева не имеет родителя) указатель на своего родителя.Несколько детей могут совместно использовать одного и того же родителя.
Если я хочу получить клон значения из этой цепочки хеш-карты, я использую рекурсию для перехода по дереву, например:
impl<T> Node<T> {
pub fn get(&self, name: &str) -> Option<T> {
self.vals
.get(name)
.cloned()
.or_else(|| self.parent.as_ref().and_then(|p| p.borrow().get(name)))
}
}
Однако мне нужна изменяемая ссылка на элемент, содержащийся в этом дереве.Так как я не могу вернуть 'стандартную' изменяемую ссылку на элемент, из-за того, что он содержится в RefCell,
, я подумал об использовании RefMut
и функции RefMut::map
для его получения, например:
use std::cell::RefMut;
impl<T> Node<T> {
pub fn get_mut<'a>(node: RefMut<'a, Node<T>>, name: &str) -> Option<RefMut<'a, T>> {
if node.vals.contains_key(name) {
Some(RefMut::map(node, |n| n.vals.get_mut(name).unwrap()))
} else {
node.parent.and_then(|p| Node::get_mut(p.borrow_mut(), name))
}
}
}
Это не компилируется: возвращаемое значение ссылается на его дочерний узел (поскольку оно также зависит от заимствования его дочернего элемента), а указатель RefMut
, указывающий на дочерний элемент, выходит из области действия при выходе из функции:
error[E0515]: cannot return value referencing function parameter `p`
--> src/lib.rs:16:31
|
16 | .and_then(|p| Node::get_mut(p.borrow_mut(), name))
| ^^^^^^^^^^^^^^-^^^^^^^^^^^^^^^^^^^^
| | |
| | `p` is borrowed here
| returns a value referencing data owned by the current function
error[E0507]: cannot move out of borrowed content
--> src/lib.rs:15:13
|
15 | node.parent
| ^^^^^^^^^^^ cannot move out of borrowed content
Я не понимаю, как я мог получить что-то достойное от этого дерева.Я предполагаю, что мне может понадобиться своего рода «RefMut
цепочка», чтобы продлить время жизни дочернего узла RefMut
, но разве это также не создаст несколько изменяемых ссылок на (компоненты) одного и того же Node
?
В качестве альтернативы, есть ли способ получить что-то вроде Rc<RefCell>
, указывающее на одно из значений в узле, чтобы избежать такого рода цепочки зависимостей?Я действительно озадачен тем, что делать.
Пожалуйста, не предлагайте передавать функцию для применения к значению с заданным именем, а не возвращать ссылку, поскольку это не относится к моему случаю использования: я действительномне нужна только изменяемая ссылка (или что-то, что позволяет мне ее получить).
Я не верю, что это дубликат Как мне вернуть ссылку на что-то внутри RefCell, не нарушая инкапсуляцию?, так как этот ответ имеет дело только с возвратом ссылки на компонент значения, содержащегося в одном RefCell
(который я уже использую RefMut::map
).Моя проблема связана с цепочкой Rc<RefCell>
s, к которой этот вопрос не относится.