SoFunction
Updated on 2025-03-05

A brief discussion on a hidden function of defer in go

Defer is an important feature to focus on when starting to use Go for encoding. It's very simple: in any function, prefix the call of other functions to defer to ensure that the function is executed immediately before the external function exits, and the delayed function will run even if an exception occurs to the external function and is interrupted.

However, you can also use defer to execute paired code after and before any function starts. This hidden feature is rarely mentioned in tutorials and books online. To use this function you need to create a function and make it itself return another function, and the returned function will be used as a real delay function. After the defer statement calls the parent function, add extra brackets to delay execution of the returned child function as follows:

func main() {
  defer greet()() 
  ("Some code here...")
}

func greet() func() {
  ("Hello!")
  return func() { ("Bye!") } // this will be deferred
}

Output the following:

Hello!
Some code here...
Bye!

The function returned by the parent function will be the actual delay function. Other code in the parent function will be executed immediately at the beginning of the function (determined by where the defer statement is placed).

What abilities does this provide for developers? Because anonymous functions defined within a function can access the complete lexical environment, this means that internal functions defined in the function can refer to the function's variables. As you can see in the next example, the parameter variables are accessible within the first execution of the measure function and its delayed execution subfunction:

func main() {
  example()
  otherExample()
}

func example(){
  defer measure("example")()
  ("Some code here")
}

func otherExample(){
  defer measure("otherExample")()
  ("Some other code here")
}

func measure(name string) func() {
  start := ()
  ("Starting function %s\n", name)
  return func(){ ("Exiting function %s after %s\n", name, (start)) }
}

Output the following:

Starting example
Some code here
Exiting example after 0s
Starting otherExample
Some other code here
Exiting otherExample after 0s

In addition, the return value named by the function is also a local variable in the function. Therefore, if the measure function in the above example receives the named return value as a parameter, the named return value is accessed in the delayed execution function, so that the measure function can be transformed into a tool function that records the parameters and return values.

The following example is a snippet of the code in "Go Language Programming":

func bigSlowOperation() {
  defer trace("bigSlowOperation")() // don't forget the extra parentheses
  // ...lots of work…
  (10 * ) // simulate slow
  operation by sleeping
}
func trace(msg string) func() {
  start := ()
  ("enter %s", msg)
  return func() { 
    ("exit %s (%s)", msg,(start)) 
  }
}

It is conceivable that delaying the code at the entry and exit of a function is a very useful function, especially when debugging the code.

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.