error[E0597]: `cnc_start` does not live long enough
--> plc/src/lib.rs:78:40
|
78 | .and_then(move |(blocks, runtime)| cnc_start.borrow_mut().start().map(|_| (blocks, runtime)))
| ^^^^^^^^^ borrowed value does not live long enough - `cnc_start` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are created
and_then - принимает FnOnce и в замыкание передано значение. Что не так?
note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped.
Так что это не баг, а фича.
Судя по всему match создает неявную временную переменную, которая дропается после переменных объявленных в его блоке.
Т.е. происходит что-то вроде этого:
let t;
let a = Arc::new(Mutex::new(String::new()));
t = a.lock();
match t {_ => {}}
Получим почти тоже самое сообщение об ошибке:
error[E0597]: `a` does not live long enough
--> src/lib.rs:6:9
|
6 | t = a.lock();
| ^ borrowed value does not live long enough
7 | match t {_ => {}}
8 | }
| -
| |
| `a` dropped here while still borrowed
Не знаю что мешает создавать временную переменную как все нормальные люди:
let a = Arc::new(Mutex::new(String::new()));
let t = a.lock();
match t {_ => {}}
Мне не удаётся воспроизвести этот эффект с простыми ссылками. Работает (в смысле выдает ошибку) только с Mutex и RefCell.
И даже с самодельным RefCell (все скопировано из std::cell) ошибка не воспроизводится. А если раскоментировать стандартый RefCell Rust начинает ругаться.
Это магия какая-то? Или я что-то делаю не так?
Нашел что это за магия. Все дело в типаже Drop. Если его заимплементить для MyBorrowRef из примера выше, то самодельный RefCell начинает работать также как стандартный.
Вот пример воспроизводящий эту багофичу без всяких Mutex-ов и RefCell-ов:
struct MyRefHaveDrop<'x>(&'x usize);
impl Drop for MyRefHaveDrop<'_> {
#[inline]
fn drop(&mut self) {}
}
fn main() {
let data = 451;
match MyRefHaveDrop(&data) { _ => {} }
}
Структура со ссылкой, для которой реализован Drop, уничтожается позже чем данные на которые она ссылается.
Такой же эффект наблюдается если заменить match на if let.
P.S.: По-моему это очень плохая фича. Она позволяет ломать компиляцию зависимых крейтов. Добавил реализацию Drop к публичной структуре и всё.
Если такое поведение match нельзя исправить, то компилятору стоило бы выдавать ошибку для всех типов независимо от наличия у них типажа Drop.
P.P.S.: Хотя если подумать, то Drop-ом можно сломать вообще все что угодно.