В каком порядке Rust уничтожает несколько локальных переменных, если они находятся в одной области видимости?
Локальные переменные Rust уничтожаются в порядке, обратном порядку их объявления: последняя созданная переменная освобождается первой. Это правило обеспечивает стекоподобное управление ресурсами и позволяет более поздним объектам безопасно использовать более ранние до завершения своей жизни.
Такой подход продолжает идею RAII: ресурс связывается с временем жизни объекта, а освобождается автоматически при выходе объекта из области видимости. В Rust это встроено в модель владения, поэтому для обычных ресурсов не требуется сборщик мусора и не нужно вручную вызывать освобождение.
Обратный порядок особенно важен для объектов, чья корректная работа зависит от ранее созданных ресурсов. Он соответствует вложенности владения: сначала завершается жизнь наиболее позднего локального объекта, затем более ранних.
Если порядок уничтожения был бы произвольным, объект мог бы быть освобождён раньше зависимого от него объекта. Это создало бы риск обращения к уже недействительному ресурсу или некорректного завершения операций очистки.
В прикладном коде такой эффект заметен при работе с блокировками, временными файлами, соединениями и охранными объектами. Ошибка в порядке объявления может привести не к нарушению памяти, а к изменению момента освобождения ресурса и, например, к удержанию блокировки дольше ожидаемого.
Для локальных переменных действует правило обратного порядка объявления. Если сначала создан ресурс A, а затем ресурс B, то при выходе из области видимости сначала вызывается очистка B, затем A.
В этом примере сначала будет освобождён second, затем first. Для типов, реализующих Drop, в этот момент вызывается их метод drop; после этого Rust завершает освобождение самого значения.
Правило относится к локальным переменным в одной области видимости. Отдельные области, временные значения, поля структур и элементы кортежей имеют собственные правила времени жизни: например, поля структуры уничтожаются в порядке объявления полей. Переменная также может быть уничтожена раньше конца области, если компилятор видит, что её больше нельзя использовать; это не следует путать с гарантированным порядком объявления при обычном завершении области и с оптимизациями, не меняющими наблюдаемую корректность программы.
Представим функцию, которая создаёт блокировку и объект, чья очистка должна выполняться до снятия этой блокировки. Если охранный объект блокировки объявлен первым, а зависимый ресурс — вторым, обратный порядок уничтожения обычно даёт нужную последовательность: сначала освобождается зависимый ресурс, затем блокировка.
Можно было бы вызвать очистку вручную, но это усложняет обработку ранних возвратов и паники, а повторная очистка может стать ошибкой. Можно также ограничить ресурс дополнительным блоком, что делает границу жизни явной, но добавляет структуру кода. Практичное решение — объявлять ресурсы в порядке зависимости и использовать отдельные области для явно более раннего освобождения; тогда результат достигается автоматически и сохраняется при выходе по ошибке.
Нет. Локальные переменные уничтожаются в обратном порядке объявления. Поля структуры уничтожаются в порядке их объявления, а не в обратном порядке. Поэтому нельзя переносить правило для локальных переменных на поля без отдельной проверки семантики типа.
Drop у переменной, если она была перемещена?Нет, перемещённая переменная больше не владеет значением и не уничтожает его повторно. Drop вызывается для фактического владельца значения — например, для переменной, в которую оно было перемещено. Это предотвращает двойное освобождение ресурса.
Не всегда. Компилятор может завершить жизнь значения после последнего использования, если это не нарушает наблюдаемое поведение программы. Если конкретный момент освобождения важен, следует использовать вложенную область или явное управление границей жизни, а не полагаться только на конец функции.