This is a creation in Article, where the information may have evolved or changed.
Defer is a keyword in the Golang language that is used for the release of a resource and is called before the function returns. The following patterns are generally used:
F,err: = os. Open (filename) if err! = Nil { panic (err)}defer f.close ()
If there are multiple defer expressions, the call order is similar to the stack, and the more subsequent defer expressions are called first.
However, if the defer is not well understood, it may be possible to step on some pits, especially when used with named return parameters. Before explaining the implementation of defer, take a look at the problems that are easily encountered with defer.
Let's take a look at a few examples. Example 1:
Func f () (result int) { defer func () { result++ } () return 0}
Example 2:
Func f () (r int) { T: = 5 defer func () { t = t + 5 } () return T}
Example 3:
Func f () (r int) { defer func (r int) { R = R + 5 } (r) return 1}
Ask the reader not to run the code, run through the results in mind, and then verify.
The correct answer to Example 1 is not 0, the correct answer for example 2 is not 10, if the correct answer to Example 3 is not 6 ...
The defer is executed before the return. This is clearly stated in the official documentation. To use defer without stepping on the pit, the most important thing is to understand that return XXX This statement is not an atomic directive!
The procedure for returning a function is to assign a value to the return value first, then call the defer expression, and finally return to the calling function.
The defer expression may modify the return value after the function return value has been set, before returning to the calling function, so that the final function return value is inconsistent with what you imagined.
In fact, when using defer, with a simple conversion rule rewrite, you will not be confused. The rewrite rule is to break the return statement into two sentences, and return XXX will be rewritten as:
return value = XXX Call defer function empty return
First Look at example 1, which can be rewritten like this:
Func f () (result int) { result = 0 //return statement is not an atomic call, return XXX is actually an assignment +ret instruction func () {//defer is inserted before the return execution, That is, the assignment return value and the RET instruction between result++ } () return}
So this return value is 1.
Look again at Example 2, which can be rewritten like this:
Func f () (r int) { T: = 5 r = t//assignment Instruction func () { //defer is inserted between assignment and return execution, the return value R in this example has not been modified t = t + 5 }< C12/>return //null return instruction}
So the result of this is 5.
Finally look at example 3, which is rewritten to become:
Func f () (r int) { R = 1 //assigns the return value func (r int) { //here R is a value passed in R, does not change the R value to be returned r = R + 5 } (r) re Turn //Empty return}
So the result of this example is 1.
Defer is actually called before the return. But the form of expression may not be like. The essential reason is that the return XXX statement is not an atomic instruction, defer is inserted between the assignment and the RET, so there may be a chance to change the final return value.
The realization of defer
The implementation of the DEFER keyword is very similar to the GO keyword, but the difference is that it calls Runtime.deferproc instead of Runtime.newproc.
Where defer appears, it inserts the command call Runtime.deferproc, and then inserts the command call Runtime.deferreturn where it was before the function returns.
When the normal function returns, the assembly code is similar:
Add xx spreturn
If the defer statement is included, the assembly code is:
Call Runtime.deferreturn,add xx Spreturn
In the control structure of Goroutine, there is a table recording defer, When you call Runtime.deferproc, the expression that needs to be defer is recorded in the table, and when Runtime.deferreturn is called, it is sequentially out of the defer table and executed.