I have a tree-like structure like the following:
use std::{cell::RefCell, collections::HashMap, rc::Rc};
struct Node<T> {
vals: HashMap<String, T>,
parent: Option<Rc<RefCell<Node<T>>>>,
}
This is a chained hash map: each node contains a hash map and an (optional, as the root of the tree has no parent) shared pointer to its parent. Multiple children can share the same parent.
If I want to get a clone of a value out of this chained hash map, I use recursion to walk up the tree, like so:
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)))
}
}
However, I need a mutable reference to an element contained in this tree. Since I cannot return a 'standard' mutable reference to an element, due to it being contained in a RefCell,
I thought about using RefMut
and the RefMut::map
function to obtain one, like so:
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))
}
}
}
This does not compile: the return value references its child node (due to it being also dependent on its child's borrow), and the RefMut
pointing to the child goes out of scope at function exit:
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
I do not understand how I could go about getting something deferenceable out of this tree. I assume I might need a sort of "RefMut
chain" in order to extend the lifetime of the child node RefMut
, but wouldn't that also create multiple mutable references to (components of) the same Node
?
Alternatively, is there a way to get some sort of Rc<RefCell>
pointing to one of the values in a node, as to avoid this sort of dependency chain? I really am stumped as to what to do.
Please do not suggest passing a function to apply to the value with the given name rather than returning a reference, as that does not apply to my use case: I really do need just a mutable reference (or something allowing me to obtain one.)
I do not believe that this is a duplicate of How do I return a reference to something inside a RefCell without breaking encapsulation?, as that answer only deals with returning a reference to a component of a value contained in a single RefCell
(which I already do using RefMut::map
). My problem involves a chain of Rc<RefCell>
s, which that question does not address.