Изменчивый заем выходит за рамки, но не может повторно заимствовать - PullRequest
0 голосов
/ 13 ноября 2018

Мне трудно понять, почему я не могу использовать v во второй раз, когда кажется, что первый изменяемый заем вышел за рамки:

fn get_or_insert(v: &mut Vec<Option<i32>>, index: usize, default: i32) -> &mut i32 {
    if let Some(entry) = v.get_mut(index) { // <-- first borrow here
        if let Some(value) = entry.as_mut() {
            return value;
        }
    }

    // error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable    
    while v.len() <= index {                // <-- compiler error here
        v.push(None);
    }

    // error[E0499]: cannot borrow `*v` as mutable more than once at a time
    let entry = v.get_mut(index).unwrap();  // <-- compiler error here
    *entry = Some(default);
    entry.as_mut().unwrap()
}

ссылка на игровую площадку

У меня неверные области видимости или средство проверки заимствования защищает меня от чего-то, чего я не вижу?

Редактировать: сообщение об ошибке с включенным NLL довольно хорошо:

error[E0502]: cannot borrow `*v` as immutable because it is also borrowed as mutable
  --> src/main.rs:10:11
   |
3  | fn get_or_insert(v: &mut Vec<Option<i32>>, index: usize, default: i32) -> &mut i32 {
   |                     - let's call the lifetime of this reference `'1`
4  |     if let Some(entry) = v.get_mut(index) {
   |                          - mutable borrow occurs here
5  |         if let Some(value) = entry.as_mut() {
6  |             return value;
   |                    ----- returning this value requires that `*v` is borrowed for `'1`
...
10 |     while v.len() <= index {
   |           ^ immutable borrow occurs here

1 Ответ

0 голосов
/ 14 ноября 2018

Ключевым моментом является то, что, даже с NLL, время жизни возвращаемого значения охватывает всю функцию.Тот факт, что функция возвращается рано в строке 4, не учитывается при принятии решения о том, доступна ли ссылка v в коде внизу.

Исправление, предложенное @Stargateur, заключается в увеличении вектора при необходимости.перед доступом к элементу:

fn get_or_insert(v: &mut Vec<Option<i32>>, index: usize, value: i32) -> &mut i32 {
    if v.len() < index {
        v.resize(index + 1, None);
    }
    v[index].get_or_insert(value)
}

ссылка на игровую площадку

Вот где я использовал технику в конечном коде.

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