Defer, like Go, is a keyword provided by the GO language. Defer is used to release the resource and is called before the function returns. Generally, the following modes are adopted:

f,err := os.Open(filename)
iferr ! =nil {
    panic(err)
}
defer f.Close()
Copy the code

If there are multiple defer expressions, the order of invocation is similar to the stack, with the later defer expressions being invoked first.

However, if you don’t know enough about defer, it can be tricky to use, especially with named return parameters. Before explaining the implementation of defer, let’s take a look at some of the pitfalls of using defer.

Let’s look at a few examples of how to use the pits in defer. Case 1:


func f(a) (result int) {
    defer func(a) {
        result++
    }()
    return 0} case2:func f(a) (r int) {
     t := 5
     defer func(a) {
       t = t + 5} ()returnT}3:func f(a) (r int) {
    defer func(r int) {
          r = r + 5
    }(r)
    return 1
}
Copy the code

Please don’t run the code, run through the results in your mind, and then verify.

The correct answer to example 1 is not 0, the correct answer to example 2 is not 10, and if the correct answer to example 3 is not 6……

Defer is executed before return. This is clearly stated in the official documentation. The most important thing to understand when using defer without trampling is that the return XXX statement is not an atomic instruction!

The function returns by assigning the return value, calling the defer expression, and finally returning to the calling function.

The defer expression might modify the return value of the function after setting it, but before returning to the calling function, so that the final function return is not what you expected.

When you use defer, you can rewrite it with a simple transformation rule so you don’t get confused. Return XXX will be rewritten as:

Return value = XXX

Call the defer function

The return of the empty

Let’s start with Example 1, which can be rewritten like this:

func f(a) (result int) {
     result = 0  // the return statement is not an atomic call, return XXX is actually an assignment +ret instruction
     func(a) { //defer is inserted before the return, between the assignment return value and the ret directive
         result++
     }()
     return} so the return value is1. Then look at case2, it can be rewritten like this:func f(a) (r int) {
     t := 5
     r = t // Assign instruction
     func(a) {        //defer is inserted between assignment and return; in this case, the return value r has not been modified
         t = t + 5
     }
     return        // Empty return directive} So the result of this is5. Finally see case3, it was rewritten to become:func f(a) (r int) {
     r = 1  // Assign the return value
     func(r int) {        // The r that is passed in does not change the r that is returned
          r = r + 5
     }(r)
     return        / / return empty} So the result of this example is1.Copy the code

Defer is indeed called before the return. But the form may not. The essence is that the return XXX statement is not an atomic instruction, and defer is inserted between assignment and RET, so there may be an opportunity to change the final return value.