Оператор defer
Оператор defer откладывает выполнение функции до тех пор, пока не завершится функция, в которой он был вызван. Это удобно для выполнения операций очистки, закрытия файлов или освобождения ресурсов. Отложенная функция выполняется в любом случае, даже если возникла паника.
Синтаксис
godefer functionCall()
После ключевого слова defer указывается вызов функции или метода, который будет выполнен после завершения окружающей функции.
Пример использования defer
Давайте рассмотрим простой пример использования defer для выполнения действия перед завершением функции:
gopackage main
import "fmt"
func main() {
defer fmt.Println("World")
fmt.Println("Hello")
}
Результат выполнения кода:
goHello
World
Несмотря на то что вызов defer находится перед выводом "Hello", отложенная функция выполняется после завершения функции main, поэтому сначала выводится "Hello", а затем "World".
Пример с закрытием файла
Часто defer используется для гарантированного закрытия ресурсов, таких как файлы или сетевые соединения:
gopackage main
import (
"fmt"
"os"
)
func main() {
file, err := os.Create("example.txt")
if err != nil {
fmt.Println("Error:", err)
return
}
defer file.Close()
file.WriteString("Hello, World!")
fmt.Println("File written successfully")
}
Результат выполнения кода:
go"File written successfully"
Файл будет закрыт автоматически при выходе из функции main, даже если произойдет ошибка или паника.
Порядок выполнения отложенных функций
Если в функции указано несколько операторов defer, они выполняются в порядке, обратном их объявлению (LIFO - Last In First Out):
gopackage main
import "fmt"
func main() {
defer fmt.Println("Third")
defer fmt.Println("Second")
defer fmt.Println("First")
fmt.Println("Main function")
}
Результат выполнения кода:
goMain function
First
Second
Third
Отложенные функции выполняются в обратном порядке: последний объявленный defer выполняется первым.
Пример с паникой
Отложенная функция выполняется даже при возникновении паники, что позволяет безопасно освободить ресурсы:
gopackage main
import "fmt"
func main() {
defer fmt.Println("Deferred function executed")
fmt.Println("Before panic")
panic("Something went wrong")
fmt.Println("After panic")
}
Результат выполнения кода:
goBefore panic
Deferred function executed
panic: Something went wrong
...
Несмотря на панику, отложенная функция выполняется перед завершением программы.
Пример с изменяемыми аргументами
Аргументы отложенной функции вычисляются в момент вызова defer, а не в момент выполнения:
gopackage main
import "fmt"
func main() {
i := 0
defer fmt.Println("Deferred value:", i)
i = 42
fmt.Println("Current value:", i)
}
Результат выполнения кода:
goCurrent value: 42
Deferred value: 0
Переменная i была изменена после объявления defer, но отложенная функция запомнила ее значение на момент вызова defer.