Ответ
Да, безусловно. В одной функции можно использовать неограниченное количество операторов defer
.
Они выполняются в порядке, обратном их объявлению, по принципу LIFO (Last-In, First-Out). Можно представить, что каждый вызов defer
помещает функцию в стек, и по завершении родительской функции они извлекаются из стека и выполняются одна за другой.
Простой пример для демонстрации порядка:
package main
import "fmt"
func main() {
fmt.Println("Начало выполнения функции")
defer fmt.Println("Выполнится последним (первый defer)")
defer fmt.Println("Выполнится вторым (второй defer)")
defer fmt.Println("Выполнится первым (третий defer)")
fmt.Println("Завершение выполнения функции")
}
/*
Вывод:
Начало выполнения функции
Завершение выполнения функции
Выполнится первым (третий defer)
Выполнится вторым (второй defer)
Выполнится последним (первый defer)
*/
Почему важен порядок LIFO? (Практический пример)
Этот порядок очень удобен для корректного освобождения ресурсов. Ресурсы, которые были захвачены последними, должны освобождаться первыми.
Например, вы открываете файл, а затем блокируете мьютекс для безопасной работы с ним. Освобождать ресурсы нужно в обратном порядке: сначала разблокировать мьютекс, а потом закрыть файл.
func processFile(filename string) error {
file, err := os.Open(filename)
if err != nil {
return err
}
// defer для закрытия файла будет вызван вторым
defer file.Close()
mu.Lock()
// defer для разблокировки мьютекса будет вызван первым
defer mu.Unlock()
// ... какая-то работа с файлом внутри критической секции ...
return nil
}
Благодаря defer
и порядку LIFO, вам не нужно беспокоиться о ручном освобождении ресурсов в правильной последовательности перед каждым return
.