SoFunction
Updated on 2025-03-05

Summary of the trap used by defer in Go language

01 Introduction

What is defer

defer is a mechanism provided by the Go language for registering delayed calls to ensure that some resources are recycled and released.

Defer registered delayed call can be executed after the current function is executed (including the normal ending through return or the exception ending caused by panic)

When the function or expression registered by defe is executed in reverse order, the one registered first and then executed, similar to the stack "first in, then out"

Let's see an example below:

package main

import "fmt"

func main() {
   f()
}

func f() {
   defer func() {
      (1)
   }()
   defer func() {
      (2)
   }()
   defer func() {
      (3)
   }()
}

Output:

3
2
1

How to use defer

Free up resources

Using defer can avoid resource leakage to a certain extent, especially in scenarios where there are many return statements. It is easy to forget or the resource is not closed due to logical errors.

The following program is because the statement that closes the resource is not executed after using return, resulting in resource leakage:

f, err := ("")
if err != nil {
   return
}
()
()

Better here are as follows:

f, err := ("")
if err != nil {
   return
}
defer ()

// Operate the filef,process()

Here, when the program executes smoothly, defer will release resources; defer needs to be registered first and then used. For example, when the file is opened, the current function will be exited when the program executes the return statement without defer, so defer will not be executed here

defer catches exception

There is no try and catch in go, and when the program has an exception, we need to recover from the exception. At this time, we can use defer + recover for exception capture

func f() {
    defer func() {
       if err := recover(); err != nil {
          (err)
       }
    }()
    // do something
    panic("panic")
}

Note that the recover() function is only valid when called with anonymous function in defer, and the following programs cannot perform exception capture:

func f() {
    if err := recover(); err != nil {
        (err)
    }
    //  do something
    panic("panic")
}

Implement code tracking

The following provides a method to trace information about entering or leaving a function when a program is reached. This can be used to test whether a specific function has been executed.

func trace(msg string) { ("entering:", msg) }
func untrace(msg string) { ("leaving:", msg) }

Record the parameters and return values ​​of the function

Sometimes the program returns the result that does not meet expectations. You may manually print log debugging. At this time, use defer to record the parameters and return values ​​of the function to avoid manually printing debugging statements.

func func1(s string) (n int, err error) {
    defer func() {
        ("func1(%q) = %d, %v", s, n, err)
    }()
    return 7, nil
}

Implement code tracking and record the parameters and return values ​​of the function

In Go language, defer is generally used to release resources, or to use defer to call an anonymous function, and use recover() to handle exception panic in anonymous functions.

When using defer, it is also easy to encounter traps. In this article, we will introduce the traps when using defer.

02 defer trap

The defer statement cannot be followed by the return statement.

Sample code:

func main() {
    name := GetUserName("phper")
    ("name:%s\n", name)
    if name != "gopher" {
        return
    }
    defer ("this is a defer call")
}

func GetUserName(name string) string {
    return name
}

Output result:

name:phper

Read the above code, we execute the defer statement after the return statement. By outputting the result, we can find that the defer statement call is not executed.

Although defer can be anywhere in the function body, we also need to pay special attention to whether the position where defer can be executed.

The defer statement executes anonymous functions and preprocesses parameters.

Sample code:

func main() {
    var count int64
    defer func(data int64) {
        ("defer:", data)
    }(count + 1)
    count = 100
    ("main:", count)
}

Output result:

main: 100
defer: 1

Reading the above code, first we define a variable count of type int64, and then use the defer statement to execute an anonymous function. The anonymous function passes the parameter count + 1, and finally the main function outputs 100, and the anonymous function executed by defer outputs 1.

Because when executing the defer statement, count + 1 is executed, and it is stored first, and wait until the main function where defer is located is executed, and then execute the code in the function body of the anonymous function called by the defer statement.

03 Summary

This article mainly introduces the pitfalls you may encounter when using defer statements. The defer statement cannot be after the return statement; the anonymous functions executed by the defer statement, and the parameters of the anonymous function will be pre-processed.

This is the end of this article about the traps of defer use in Go. For more relevant content on defer use in Go, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!