Вставить в HashMap на основе другого значения в том же Hashmap - PullRequest
0 голосов
/ 07 мая 2020

Я пытаюсь вставить значение в HashMap на основе другого значения в том же HashMap, например:

use std::collections::HashMap;

fn main() {
    let mut some_map = HashMap::new();
    some_map.insert("a", 1);

    let some_val = some_map.get("a").unwrap();

    if *some_val != 2 {
        some_map.insert("b", *some_val);
    }
}

, что дает это предупреждение:

warning: cannot borrow `some_map` as mutable because it is also borrowed as immutable
  --> src/main.rs:10:9
   |
7  |     let some_val = some_map.get("a").unwrap();
   |                    -------- immutable borrow occurs here
...
10 |         some_map.insert("b", *some_val);
   |         ^^^^^^^^             --------- immutable borrow later used here
   |         |
   |         mutable borrow occurs here
   |
   = note: `#[warn(mutable_borrow_reservation_conflict)]` on by default
   = warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
   = note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>

If Вместо этого я пытался обновить существующее значение, я мог бы использовать внутреннюю мутацию и RefCell, как описано здесь .

Если бы я пытался вставить или обновить значение на основе самого , я мог бы использовать API ввода, как описано здесь .

Я мог бы обойти проблему с клонированием, но я предпочел бы избежать этого, поскольку полученное значение в моем фактическом коде несколько сложно. Потребуется ли для этого небезопасный код?

1 Ответ

0 голосов
/ 07 мая 2020

ИЗМЕНИТЬ Поскольку предыдущий ответ просто неверен и вообще не отвечает на вопрос, есть код, который не показывает никаких предупреждений ( игровая площадка )

Теперь это хэш-карта со значениями Rc<_>, а val_rc содержит только счетчик ссылок на фактические данные (в данном случае номер 1). Поскольку это всего лишь счетчик, его клонирование бесплатно. Однако обратите внимание, что существует только одна копия числа, поэтому, если вы измените значение some_map["a"], то some_map["b"] также изменится, поскольку они относятся к одной части памяти. Также обратите внимание, что 1 живет в стеке, поэтому вам лучше подумать о том, чтобы превратить его в Rc<Box<_>>, если вы планируете добавить много тяжелых объектов.

use std::collections::HashMap;
use std::rc::Rc;

fn main() {
    let mut some_map = HashMap::new();
    some_map.insert("a", Rc::new(1));

    let val_rc = Rc::clone(some_map.get("a").unwrap());
    if *val_rc != 2 {
        some_map.insert("b", val_rc);
    }

}

Предыдущая версия ответа

Трудно сказать, что именно вы ищете, но в этом конкретном случае, если вам нужно только проверить значение, уничтожьте заимствованное значение, прежде чем обновлять хэш-карту. Грязный и уродливый код будет таким:

fn main() {
    let mut some_map = HashMap::new();
    some_map.insert("a", 1);

    let is_ok = false;

    {
        let some_val = some_map.get("a").unwrap();
        is_ok = *some_val != 2;
    }

    if is_ok {
        some_map.insert("b", *some_val);
    }
}
...