Как получить изменяемую структуру из HashMap?

У меня есть хэш-карта для всех моих состояний, которая является HashMap<String, Rc<State>>, и я хочу вызвать член текущего состояния fn init(&mut self). Но я получаю сообщение об ошибке со следующим кодом:

...
if let Some(state) = self.states.get_mut(state_id) {
    (*state).init();
}
...

Вот ошибка:

src/main.rs:70:25: 70:33 error: cannot borrow immutable borrowed content as mutable
src/main.rs:70                         (*state).shutdown();`

Как видно из документации, проблема в том, что get_mut возвращает изменяемую ссылку на состояние, а не ссылку на изменяемое состояние. Итак, как мне получить ссылку на изменяемое состояние?


person Shien    schedule 03.08.2015    source источник
comment
if let Some(mut state) = self.states.get_mut(state_id) { помогает?   -  person tilpner    schedule 03.08.2015
comment
Нет, пробовал уже. О, и я заработал, используя RefCell, но я бы предпочел не использовать их, потому что они медленнее и могут легко запаниковать, если я не буду очень осторожен.   -  person Shien    schedule 03.08.2015
comment
Похоже, вам нужна внутренняя изменчивость. Пример детского манежа   -  person tilpner    schedule 03.08.2015
comment
Да, я просто надеялся, что есть статическое решение. знак равно   -  person Shien    schedule 03.08.2015
comment
Это было бы возможно, если бы вы не использовали Rc, но даже документацию Rc использует RefCells для внутренней изменчивости.   -  person tilpner    schedule 03.08.2015
comment
да это не имеет ничего общего с HashMap. Rust не может рассуждать об изменчивости внутреннего значения Rc, поэтому он запрещает мутацию, пока Rc не уникален. Вы можете использовать get_mut, если есть только одна ссылка. Но тогда вы могли бы вообще бросить Rc   -  person oli_obk    schedule 03.08.2015
comment
Ваше сообщение об ошибке ссылается на код, который вы не включили.   -  person Shepmaster    schedule 03.08.2015
comment
@Shien: для статического решения вам нужно отказаться от псевдонимов; вам действительно нужно Rc?   -  person Matthieu M.    schedule 04.08.2015


Ответы (1)


Фундаментальная идея Rust: либо псевдонимы, либо изменчивость, но не то и другое одновременно.

Псевдоним означает наличие нескольких активных указателей на одно и то же значение.

Что такое Rc<T>? Это совместное владение, псевдоним значения. Таким образом, Rc<T> не позволяет изменять значение внутри.

Есть способ обойти это с помощью Rc, чтобы использовать внутреннюю изменчивость с такими типами, как Cell<U> или RefCell<U>.

(Если вы пишете многопоточную программу, вы должны использовать Arc для безопасного совместного владения потоками/псевдонимов, и вместо этого вы можете использовать Mutex<U> для безопасной внутренней изменчивости потоков.)

  • Rc<Cell<U>> позволяет изменять U, разрешая только запись и чтение, но не указатели на внутреннее значение U. Никаких указателей, никаких псевдонимов!

  • Rc<RefCell<U>> позволяет изменять метод .borrow_mut(), который будет вести подсчет заимствований во время выполнения и динамически обеспечивать эксклюзивность любого изменяемого заимствования. Никаких псевдонимов, у вас есть изменчивость!

Ссылки

person bluss    schedule 03.08.2015