2

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.

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
CRefice
  • 430
  • 5
  • 11
  • Perhaps one of these: https://stackoverflow.com/questions/29401626/how-do-i-return-a-reference-to-something-inside-a-refcell-without-breaking-encap https://stackoverflow.com/questions/51341643/returning-reference-from-refcell https://stackoverflow.com/questions/30281664/how-do-i-borrow-a-refcellhashmap-find-a-key-and-return-a-reference-to-the-re https://stackoverflow.com/questions/25233925/cant-figure-out-a-function-to-return-a-reference-to-a-given-type-stored-in-refc – Peter Hall Jan 29 '19 at 18:46
  • Possible duplicate of [How do I return a reference to something inside a RefCell without breaking encapsulation?](https://stackoverflow.com/questions/29401626/how-do-i-return-a-reference-to-something-inside-a-refcell-without-breaking-encap) – Peter Hall Jan 29 '19 at 18:49
  • I do not believe it is a duplicate: that question involves getting a reference from a single RefCell (which I already use in the code posted with my question), my question involves getting one from a RefCell chain – CRefice Jan 29 '19 at 18:51

0 Answers0