SoFunction
Updated on 2025-04-11

The execution order of nested defers in go language for loop

In Go,deferA statement is used to delay the execution of a function call until the function containing it returns. whendeferStatements nested inforWhen in a loop, its execution timing still followsdeferThe basic rules of , but pay attention to the context returned by the loop and function.

Basic Rules

  • Delayed executiondeferA statement will be executed when the function containing it returns, regardless of whether the function returns normally or due to errors, panics, etc.
  • Last In First Out (LIFO): If there are multipledeferstatements, they will be executed in the order of back in first out.

Use defer in for loop

whendeferStatements nested inforWhen in a loop, its execution timing is related to the context of the loop:

1. The defer in the body

ifdeferThe statement is located inforInside the loop body, it is recorded at the end of each loop iteration, but the actual execution time depends on when the function where the loop is located returns.

2. Execute when the function returns

No matter how many times the loop is executed,deferStatements are executed in the order of records when the function containing it returns.

Sample code

Here is a sample code to help understanddeferexistforBehavior in a loop:

package main

import "fmt"

func main() {
    for i := 0; i < 3; i++ {
        defer ("Deferred in loop iteration:", i)
    }
    ("Loop finished")
}

Output result:

Loop finished
Deferred in loop iteration: 2
Deferred in loop iteration: 1
Deferred in loop iteration: 0

explain:

  • Circulate in the bodydeferThe statement is recorded at the end of each iteration.
  • After the loop is over, the program continues to execute untilmainThe function returns.
  • existmainWhen the function returns,deferThe statement is executed in the order of the last iteration first, that is, the last iteration is executed first.defer, execute the previous one again, and so on.

Things to note

  • Performance issues: Use frequently in loopsdeferThis may cause performance issues, as a delayed call is logged in each iteration.
  • Variable Capture:ifdeferThe statement captures loop variables (e.g.i), which may lead to unexpected behavior. For example, ifdeferWhat is captured is a reference to a variable, not a value, which may result in alldeferThe statement prints the same value.

If inforNested in a loopdeferA call is a function, rather than directly printing the value, the output result may vary depending on the implementation of the function. In particular, if the variable is captured inside the function (such as loop variablesi), which may lead to some unexpected behavior.

Example 1: defer call a function to capture the value of a loop variable

If the function captures the value of the loop variable (passed through parameters), then each calldeferThe value of the current iteration will be recorded. In this case, the output result is similar to the direct printing value.

package main

import "fmt"

func printDeferred(value int) {
    ("Deferred value:", value)
}

func main() {
    for i := 0; i < 3; i++ {
        defer printDeferred(i)
    }
    ("Loop finished")
}

Output result:

Loop finished
Deferred value: 2
Deferred value: 1
Deferred value: 0

explain:

  • Each iteration,deferCalledprintDeferredfunction and the current oneiPassed as a parameter to the function.
  • The function captures the value of the variable, so the value of the current iteration is recorded in each iteration.
  • When the function returns,deferExecute in the order of first out.

Example 2: defer call a function to capture references to loop variables

If the function captures a reference to a loop variable (such as using variables directlyi, instead of passing values ​​through parameters), then alldeferThe output of the call may be the same because they all refer to the same variable.

package main

import "fmt"

func printDeferred() {
    ("Deferred value:", i)
}

func main() {
    for i := 0; i < 3; i++ {
        defer printDeferred()
    }
    ("Loop finished")
}

Output result:

Loop finished
Deferred value: 3
Deferred value: 3
Deferred value: 3

explain:

  • existforIn the loop,deferCalledprintDeferredfunction, but no parameters are passed.
  • The variable is accessed directly within the function.i, so what is captured is a reference to the variable.
  • whendeferWhen executing, the loop has ended.iThe value of  is 3 (the value after the end of the loop).
  • alldeferThe calls are all printed 3 because they refer to the same variable.

Example 3: defer calls a function to capture the value of a loop variable (closure)

If the function is a closure that captures the value of the loop variable, then each iteration captures the value of the current iteration.

package main

import "fmt"

func main() {
    for i := 0; i < 3; i++ {
        defer func(value int) {
            ("Deferred value:", value)
        }(i)
    }
    ("Loop finished")
}

Output result:

Loop finished
Deferred value: 2
Deferred value: 1
Deferred value: 0

explain:

  • Each iteration,deferAn anonymous function was called and the current one wasiPassed as a parameter to the closure.
  • The closure captures the value of the variable, so the value of the current iteration is recorded in each iteration.
  • When the function returns,deferExecute in the order of first out.

Summarize

ifdeferThe call is a function, and the output result will be affected by the following factors:

  • Whether a function captures the value or reference of a variable
    • If the value is captured (passed by parameters), the value of the current iteration is recorded for each iteration.
    • If what is captured is a reference (direct access to the variable), then alldeferThe call may print the same value (value after the end of the loop).
  • Use of closures: If you use a closure to capture the value of a variable, the value of the current iteration will be recorded in each iteration.

Therefore, usedeferWhen paying attention to the details of variable capture, you need to avoid unexpected behavior.

Summarize

existforNested in a loopdeferhour,deferThe statement is recorded at the end of each iteration, but the actual execution time is when the function containing it returns. understanddeferThe execution rules and context are very important to avoid unexpected behavior.

This is the article about the execution order of nested defers in the go language for loop. For more information about the execution order of go language defers, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!