Уроки модуля (5/5)
`defer`: гарантированная очистка
defer откладывает выполнение вызова до тех пор, пока не будет включена включающая функция.
возвращается. Он запускается, даже если функция завершается из-за паники. Несколько defer
в той же функции выполняются в порядке LIFO (последний вошел, первый вышел).
Это идиоматический механизм очистки ресурсов: закрытие файлов, разблокировка мьютексов, освобождение соединений, восстановление состояния.
Синтаксис и канонический вариант использования
f, err := os.Open(path)
if err != nil {
return err
}
defer f.Close() // chiamata SEMPRE all'uscita della funzione
// ... usa f liberamente ...
return nilТипично: f.Close(), mu.Unlock(), db.Close(), tx.Rollback(),
recover().
Аргументы оцениваются немедленно, выполнение откладывается.
Когда вы пишете defer foo(x), x оценивается во время
defer, не во время выполнения:
x := 10
defer fmt.Println(x) // cattura 10
x = 99
// quando la funzione ritorna stampa "10", non "99"заказ ЛИФО
Откладывает стек и выполняет, начиная с самого последнего:
defer fmt.Println(1)
defer fmt.Println(2)
defer fmt.Println(3)
// output: 3, 2, 1Это согласуется с семантикой ресурса: последнее открытое является первым. быть закрытым.
defer + recover: обработка паники
defer — единственный способ перехватить panic:
func safe() {
defer func() {
if r := recover(); r != nil {
fmt.Println("recuperato:", r)
}
}()
panic("boom")
}Ошибка: defer в цикле
Помещение defer f.Close() в цикл накапливает отсрочки ** до конца
функция**, а не каждой итерации. В длинном цикле вы открываете много файлов
и закрывать их только при выходе из функции: риск утечки файлового дескриптора.
// MALE: defer accumulati
for _, path := range paths {
f, _ := os.Open(path)
defer f.Close() // chiude TUTTI alla fine della funzione esterna
// ...
}
// MEGLIO: estrai in una funzione
for _, path := range paths {
elabora(path) // ogni chiamata ha il proprio scope di defer
}Попробуйте это
Выведите «inizio», затем отложите печать «fine» с помощью defer, затем напечатайте «mezzo». Результат должен быть: inizio/mezzo/fine.
Показать подсказку
Отсрочка запускается, когда функция main() собирается вернуться.
Решение доступно после 3 попыток
Напишите три последовательных отсрочки, которые печатают 1, 2 и 3 в указанном порядке в коде. Выход будет 3/2/1 (ЛИФО).
Показать подсказку
Три отсрочки подряд; помните, что они выполняются в обратном порядке.
Решение доступно после 3 попыток
Что это печатает? (примечание: аргументы отсрочки оцениваются немедленно)
x := 10
defer fmt.Println(x)
x = 99Резюме
defer call()откладывает выполнение до тех пор, пока функция не вернется.- Множественные отсрочки = заказ ЛИФО.
- Аргументы оцениваются немедленно, выполнение отложено.
- Используется для детерминированной очистки: файлов, мьютексов, соединений.
defer+recover()перехватываетpanic(редко, на границах).- Никогда не используйте
deferвнутри длинного цикла: он накапливается до тех пор, пока внешняя функция не вернет результат.