SoFunction
Updated on 2025-03-04

Detailed explanation of the usage rules of defer in golang

Preface

In golang, the defer code block will add a function call to the function call linked list. This function call is not an ordinary function call, but will add a function call after the function returns normally, that is, return. Therefore, defer is usually used to release variables inside functions.

In order to better learn defer behavior, let's first look at the following code:

func CopyFile(dstName, srcName string) (written int64, err error) { 
src, err := (srcName) 
if err != nil { 
return 
}

dst, err := (dstName) 
if err != nil { 
return 
}

written, err = (dst, src) 
() 
() 
return 
}

This code can run, but there are 'safety risks'. If calleddst, err := (dstName)If it fails, the function will execute return and exit. However, the src (file handle) created earlier has not been released. The above code is very simple, so we can see at a glance that there is a problem that the file has not been released. If our logic is complicated or our code calls are too many, such errors may not be discovered in time. Using defer can prevent this from happening. Here is the code using defer:

func CopyFile(dstName, srcName string) (written int64, err error) { 
src, err := (srcName) 
if err != nil { 
return 
}
defer ()

dst, err := (dstName) 
if err != nil { 
return 
}
defer ()

return (dst, src) 
}

Through defer, we can elegantly close/clean the variables used in the code in our code. As a feature of golang cleaning variables, defer has its unique and clear behavior. The following are the three rules for using defer.

Rule 1 When defer is declared, its parameters will be parsed in real time.

We explain this rule through the following code:

func a() { 
i := 0 
defer (i) 
i++ 
return 
}

As we said above, the defer function will be called after return. So after this function is executed, shouldn't you output 1?

Readers compile and look at it by themselves, and the result is that the output is 0. why?

This is because although we define a function with variables after defer:(i). But when defer is declared, the value of its determined value has been determined. In other words, the above code is equivalent to the following code:

func a() { 
i := 0 
defer (0) //Because i=0, golang is clearly told to execute the output 0 operation when the program exits.i++ 
return 
}

To illustrate this issue more clearly, we continue to define a defer:

func a() { 
i := 0 
defer (i) //Output 0, because i is 0 at this timei++ 
defer (i) //Output 1, because i is 1 at this timereturn 
}

Through the running result, you can see the value output by defer, which is the value at the time of definition. Instead of the variable value when defer is actually executed (it is very important, if you don't understand it, it will result in inconsistent results)

But why do you output 1 first and 0 first? Look at the following rule two.

Rule 2 defer execution order is first in and then out

When multiple defer code blocks are defined at the same time, golang installation calls defer in sequence in order of first definition and then execution. Don't want to be why, that's how golang is defined. We use the following code to deepen our memory and understanding:

func b() { 
for i := 0; i < 4; i++ { 
defer (i) 
}
}

In the loop, four defer code blocks are defined in sequence. Combined with rule 1, we can clearly know what value should be output for each defer code block. Install the principle of first-in and then exit, we can see that 3210 is output in turn.

Rule Three defer can read a named return value

Let's look at the following code first:

func c() (i int) { 
defer func() { i++ }() 
return 1 
}

The output result is 12. At the beginning, we said that defer is executed after the return call. It should be clear here that the scope of the defer code block is still within the function. Combined with the above function, that is, the scope of the defer is still within the c function. Therefore, defer can still read variables in function c (if the variables in function cannot be read, then how can variable clearing be performed...).

After the return 1 is executed, the value of i is 1. At this moment, the defer code block starts to execute and performs self-increment operation on i. Therefore, output 2.

If we master the above three usage rules of defer, then when we encounter the defer code block, we can clearly know the expected results of defer.

Summarize

The above is the entire content of this article. I hope the content of this article will be of some help to your study or work. If you have any questions, you can leave a message to communicate. Thank you for your support.