Можно ли использовать в одной функции Go несколько операторов defer и в каком порядке они выполнятся?

Ответ

Да, безусловно. В одной функции можно использовать неограниченное количество операторов 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.