Почему средство проверки Rust заемов игнорирует изменяемый указатель среди параметров функции? - PullRequest
0 голосов
/ 27 октября 2019

Меня просто смутила ошибка компиляции ржавчины о времени жизни.

Предположим, фрагмент кода выглядит следующим образом:

fn process(map: &mut HashMap<String, String>, key: String) {
    match map.get_mut(&key) {
        Some(value) => println!("value: {}", value),
        None => {
            map.insert(key, String::new());
        }
    }
}

И я назвал его следующим образом:

fn main() {
    let mut map = HashMap::<String, String>::new();
    let key = String::from("name");
    process(&mut map, key);
}

Насколько я знаю (игнорируйте функцию NLL ), map.get_mut возвращает тип Option<&mut String>, в котором &mut String - это указатель заимствования, который указывает на часть карты, ауказатель живет через весь блок match. Затем внутри ветви None, map.insert(key, String::new()) автоматически создает еще один указатель &mut HashMap<String, String>, который также указывает на карту. Два указателя занимают одну и ту же карту дважды как изменяемую, поэтому она вызывает:

error[E0499]: cannot borrow `*map` as mutable more than once at a time
 --> test.rs:7:13
  |
4 |     match map.get_mut(&key) {
  |           --- first mutable borrow occurs here
...
7 |             map.insert(key, String::new());
  |             ^^^ second mutable borrow occurs here
8 |         }
9 |     }
  |     - first borrow ends here

error: aborting due to previous error

For more information about this error, try `rustc --explain E0499`.

Но мой вопрос:

Первый параметр функции fn process - это сам изменяемый указатель (&mut HashMap<String, String>), что также указывает на карту. Согласно правилу выше, когда следующая строка вызывает map.get_mut(&key), происходит второе изменяемое заимствование. Почему компилятор не выдает такую ​​ошибку (какой-либо риск безопасности памяти?):

fn process(map: &mut HashMap<String, String>, key: String)
           --- first mutable borrow occurs here
    match map.get_mut(&key)
    ^^^ second mutable borrow occurs here // the return value of type Option<&mut String>

Я новичок в ржавчине, любые советы будут оценены.

1 Ответ

2 голосов
/ 28 октября 2019

Чтобы выполнить вызов к get_mut, Rust выполняет неявное reborrow .

A reborrow эквивалентно заимствованию из изменяемой ссылки, а затемсглаживание ссылок. То есть, учитывая изменчивую ссылку типа &'a T, заимствование из нее дает &'b &'a T (обратите внимание, что существует два различных времени жизни; 'b короче 'a), а выравнивание ссылок дает &'b T.

Руст понимает, что заем с продолжительностью жизни 'b был получен из заимствования с продолжительностью жизни 'a. Таким образом, заем 'a будет заморожен до тех пор, пока заем 'b жив.

До NLL заем, полученный для вызова get_mut, будет существовать для всего блока match, поскольку get_mut возвращает значение, которое сохраняет заем активным. map.insert(...) также пытается перезагружаться с map, но, так как первое перезагружение с map все еще активно, это ошибка.

...