Понимание нелексических времен жизни при вызове функций, которые возвращают ссылку - PullRequest
3 голосов
/ 19 апреля 2020

Следующая функция работает нормально в отношении NLL

fn main() {
    let mut x = 1i32;
    let mut y = &mut x;

    let z = &mut y; 

    *y = 12;
}

Однако, если я заменю оператор let z = &mut y вызовом функции (который в основном делает то же самое), программа проверки заимствований будет жаловаться.

fn test<'a>(x:&'a mut &'a mut i32) -> &'a mut i32 {
    &mut **x
}

fn main() {
    let mut x = 1i32;
    let mut y = &mut x;

    let z = test(&mut y);

    *y = 12;
}

выдает следующую ошибку:

error[E0506]: cannot assign to `*y` because it is borrowed
  --> src/main.rs:11:5
   |
9  |     let z = test(&mut y);
   |                  ------ borrow of `*y` occurs here
10 |     
11 |     *y = 12;
   |     ^^^^^^^
   |     |
   |     assignment to borrowed `*y` occurs here
   |     borrow later used here

Ссылка, возвращаемая функцией test(), больше не используется, поэтому ее не следует считать «мертвой»?

1 Ответ

5 голосов
/ 19 апреля 2020

Давайте дадим несколько имен временам жизни в вашей программе. (Это не скомпилируется, но для демонстрационных целей.)

В вашем первом примере у нас есть две жизни, '1 и '2. Время жизни '2 длится только для одной строки, поэтому y можно использовать позже:

fn main() {
    let mut x = 1i32;      //
    let mut y = &'1 mut x; //        ^
                           //        |
    let z = &'2 mut y;     //  |'2   |'1
                           //        |
    *y = 12;               //        v
}

Во втором примере, поскольку test требует &'a mut &'a mut i32, где 'a представляет идентичные время жизни, внешняя ссылка должна жить столько же, сколько внутренняя ссылка. Вот почему мы получаем ошибку:

fn test<'a>(x:&'a mut &'a mut i32) -> &'a mut i32 {
    &mut **x
}

fn main() {
    let mut x = 1i32;        //
    let mut y = &'1 mut x;   //        ^
                             //        |
    let z = test(&'2 mut y); //  |'2   |'1
                             //  |     |
    *y = 12;                 //  v     v
}

Если мы дадим test два разных времени жизни, однако, код теперь скомпилируется нормально, потому что мы вернулись в той же ситуации, что и в первом примере:

fn test<'a, 'b>(x:&'a mut &'b mut i32) -> &'a mut i32 {
    &mut **x
}

fn main() {
    let mut x = 1i32;        //
    let mut y = &'1 mut x;   //        ^
                             //        |
    let z = test(&'2 mut y); //  |'2   |'1
                             //        |
    *y = 12;                 //        v
}
...