Как получить изменяемую ссылку на произвольный элемент в Rcдерево? - PullRequest
0 голосов
/ 29 января 2019

У меня есть древовидная структура, подобная следующей:

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, к которой этот вопрос не относится.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...