The defer keyword in Go postpones the execution of specified functions until the surrounding function exits — functions accumulate in a stack and are executed in reverse order (LIFO). This is often used for resource cleanup (files, mutexes, connections).
A feature is that all arguments of the functions passed to defer are evaluated immediately at the moment of declaration, not at execution time.
func test() { for i := 0; i < 3; i++ { defer fmt.Println(i) // Will print: 2, 1, 0 } }
What will the following code output?
func main() { for i := 0; i < 3; i++ { defer fmt.Println(i) } }
Answer:
It will output:
2
1
0
Because during each iteration, the argument i is evaluated immediately (at the moment of defer), and all values are stored in the defer stack.
Story
In a file service, it was forgotten that defer is only called on normal exit from a function. Leaks appeared if the program crashed before the defer call.
Story
In a data pipeline, there was a forgetting — defer was used in a loop to close connections, but they actually closed only after the entire function finished, not after each iteration. This led to resource exhaustion.
Story
In a logger, defer was used with an anonymous function, expecting the argument to be evaluated at the time of the call. As a result, the log at the end contained outdated information, as the values were captured earlier.