Почему я получаю «не живет достаточно долго» в возвращаемом значении? - PullRequest
0 голосов
/ 03 декабря 2018

При рассмотрении Как мне установить переменные Arc и Mutexed? , я столкнулся с проблемой, когда код, который выглядит нормально, генерирует ошибку "не хватает времени" при создании возвращаемого значения из Mutex.Простое извлечение доступа lock().unwrap() из возвращаемого объекта устраняет ошибку - но я бы хотел понять, почему в этом случае Rust жалуется на проблему с пожизненным сроком.

Мне удалось сократить код доочень простое средство воспроизведения: первая функция компилирует OK, вторая генерирует сообщение об ошибке, и они почти идентичны.

use std::sync::Mutex;

pub struct Response {
    resp: String,
}

pub fn get() -> Response {
    let body = Mutex::new("a".to_string());
    let x: std::sync::MutexGuard<_> = body.lock().unwrap();
    Response { resp: x.clone() }
}

pub fn get2() -> Response {
    let body = Mutex::new("a".to_string());
    Response {
        resp: body.lock().unwrap().clone(),
    }
}
error[E0597]: `body` does not live long enough
  --> src/lib.rs:16:15
   |
16 |         resp: body.lock().unwrap().clone(),
   |               ^^^^ borrowed value does not live long enough
17 |     }
18 | }
   | - `body` dropped here while still borrowed
   |
   = note: values in a scope are dropped in the opposite order they are created

Ответы [ 2 ]

0 голосов
/ 03 декабря 2018

Как указывается в ответе Stargateur, причина этого - время жизни временных.Хотя у Rust пока нет полной спецификации, справочник по языку все еще довольно хорош и, по крайней мере, дает подсказку для понимания поведения.Вот соответствующая часть из раздела о временных временах жизни :

[T] время жизни временных значений обычно

  • самый внутренний вложенный оператор;хвостовое выражение блока считается частью оператора, который включает в себя блок, или
  • выражение условия или условное выражение цикла, если временное создается в выражении условия if или в циклеусловное выражение while выражения.

Самым внутренним оператором body.lock().unwrap() во второй версии вашей функции является возвращаемое выражение.Вышеуказанная спецификация гласит, что это выражение «считается частью оператора, заключающего в себе блок», которого в данном случае на самом деле не существует, но оно все же дает правильную идею: все переменные, локальные для тела функции, удаляются до любые временные выражения в выражении возврата отбрасываются, поэтому body отбрасывается перед MutexGuard, который занимает body.Исправление, которое вы нашли, гарантирует, что временное хранилище будет удалено до body, поскольку локальные переменные удаляются примерно в обратном порядке их создания.

0 голосов
/ 03 декабря 2018

Используя #![feature(nll)], это дает точную ошибку:

   |
19 |         resp: body.lock().unwrap().clone(),
   |               ^^^^----------------
   |               |
   |               borrowed value does not live long enough
   |               a temporary with access to the borrow is created here ...
20 |     }
21 | }
   | -
   | |
   | `body` dropped here while still borrowed
   | ... and the borrow might be used here, when that temporary is dropped and runs the `Drop`
   | code for type `std::sync::MutexGuard`
   |
   = note: The temporary is part of an expression at the end of a block. Consider forcing
   this temporary to be dropped sooner, before the block's local variables are dropped.
   For example, you could save the expression's value in a new local variable `x` and then make
   `x` be the expression at the end of the block.

Довольно длинный BTW;) Это потому, что временное падение выпадает после тела, вы также можете сделать это:

pub fn get3() -> Response {
    let body = Mutex::new("a".to_string());
    let resp = body.lock().unwrap().clone();
    Response {
        resp,
    }
}
...