Рассмотрим этот код:
fn main() {
let mut y: u32 = 10;
let ry = &mut y;
let f = || ry;
f();
}
Это работает, потому что компилятор может определить время жизни ry
: ссылка ry
находится в той же области, что и y
.
Теперь эквивалентная версия вашего кода:
fn main() {
let mut y: u32 = 10;
let f = || {
let ry = &mut y;
ry
};
f();
}
Теперь компилятор назначает ry
время жизни, связанное с областью действия тела замыкания, а не время жизни, связанное с основным телом.
Также обратите внимание, что работает неизменяемый эталонный случай:
fn main() {
let mut y: u32 = 10;
let f = || {
let ry = &y;
ry
};
f();
}
Это связано с тем, что &T
имеет семантику копирования и &mut T
имеет семантику перемещения, см. Документация по семантике копирования / перемещения для& T / & mut T для получения более подробной информации набирает .
Отсутствующий фрагмент
Компилятор выдает проблему, связанную с временем жизни:
cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
, но, как указаноу Свена Марнача также есть проблема, связанная с запрещенным выходом из заемного контента.
Но почему компилятор не выдает эту ошибку?А именно:
cannot move out of borrowed content
Короткий ответ заключается в том, что компилятор сначала выполняет проверку типов, а затем заимствует проверку.
длинный ответ
Закрытие состоит из двух частей.:
состояние замыкания: структура, содержащая все объекты, захваченные замыканием
the логика замыкания: реализация признака FnOnce
, FnMut
или Fn
В этом случае состояние замыкания является изменяемой ссылкой y
, логика - это тело замыкания {&mut y}
, которое просто возвращает изменяемую ссылку.
При обнаружении ссылки ржавчина контролирует два аспекта:
состояние : если ссылка указывает на действительный фрагмент памяти (т. Е. Срок действия чтения);
логика : если фрагмент памятиявляется псевдонимом, другими словами, если на него указывают несколько ссылок одновременно;
Примечание tВыход из заимствованного содержимого запрещен во избежание алиасинга памяти.
rustc
компилятор выполняет свою работу через этапов , здесь приведен упрощенный рабочий процесс:
.rs input -> AST -> HIR -> hir postprocessing -> MIR -> mir postprocessing -> llvm IR -> binary
Компилятор сообщает о проблеме времени жизни, потому что rustc
сначала выполняет фазу проверки типа в hir postprocessing
, которая включает анализ времени жизни, и после этого, в случае успеха, выполняет проверку заимствования в фазе mir postprocessing
.