Defer

Что такое defer, как работает, зачем нужен?

defer - это ключевое слово в языке программирования Go, которое используется для определения функции, которая должна быть выполнена после возвращения текущей функции, но до возвращения вызвавшей ее функции. Это позволяет очистить ресурсы или выполнить другие задачи, которые необходимо выполнить после завершения основной работы функции.

Когда вызывается функция с ключевым словом defer, она не выполняется немедленно. Вместо этого она добавляется в список функций, которые будут выполняться в обратном порядке после возвращения текущей функции. Это означает, что последняя функция, вызванная с ключевым словом defer, будет выполнена первой после возврата текущей функции.

Ключевое слово defer полезно для обеспечения правильной очистки ресурсов, например, для закрытия файлов или сетевых соединений. Его также можно использовать для упрощения обработки ошибок, позволяя функции возвращать значение ошибки, а затем обрабатывать эту ошибку в одном месте после возврата функции.

Источники:

Код в defer выполняется до return или после?

Оператор defer в Go выполняется перед оператором return. Это позволяет удобно управлять ресурсами, такими как закрытие файлов или освобождение памяти, перед тем как функция завершится.

defer выполняется после того, как оператор return вычислит возвращаемые значения, но перед фактическим возвращением управления из функции.

Пример:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package main

import "fmt"

func main() {
defer fmt.Println(changePointer())
fmt.Println("Third")
}

func changePointer() string {
defer fmt.Println("Second")
fmt.Println("First")
return "Fourth"
}

Где инициализируется defer, в стеке или куче?

Дефер-вызовы в Go инициализируются в стеке, а не в куче. Когда функция, содержащая дефер-вызовы, начинает выполняться, эти вызовы помещаются в стек. Затем, когда функция завершается, стек разворачивается, и дефер-вызовы выполняются в обратном порядке, в котором они были помещены в стек. Это позволяет гарантировать, что ресурсы, такие как файлы или соединения, будут освобождены в правильном порядке, даже если в функции произойдет ошибка.

Задача #1

title
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"fmt"
)

func main() {
tmp := 101
fmt.Println(tmp)
defer func() {
fmt.Println(tmp)
}()
tmp = 202
return
}

Этот код использует концепцию “замыкания”. Замыкание - это функция, которая имеет доступ к переменным из своего внешнего контекста.
В данном случае, анонимная функция, которая откладывается с помощью defer, имеет доступ к переменной tmp из внешнего контекста.

Когда вы вызываете defer func() { fmt.Println(tmp) }(), функция “захватывает” текущее значение tmp на момент вызова.

Однако в этом случае tmp является ссылкой на переменную во внешнем контексте. Это значит, что если tmp изменяется после вызова defer, то измененное значение будет использоваться в отложенной функции.

tmp сначала устанавливается в 101, затем выводится, затем откладывается функция, которая выводит tmp, и наконец tmp изменяется на 202.
Когда функция main завершается, отложенная функция вызывается и выводит текущее значение tmp, которое теперь равно 202.
В результате, вывод программы будет 101 и 202.

Задача #2

title
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package main

import (
"fmt"
)

func main() {
tmp := 101
fmt.Println(tmp)
defer func(tmpx int) {
fmt.Println(tmpx)
}(tmp)
tmp = 202
return
}

В этом примере мы передаем tmp в отложенную функцию как аргумент. Это означает, что значение tmp будет скопировано в отложенную функцию, а не ссылаться на переменную во внешнем контексте.

В результате, вывод программы будет 101 и 101.

Вот вам и defer

Поделиться