This is a creation in Article, where the information may have evolved or changed.
1 Official definition
A defer statement pushes a function call onto a list. The list of saved calls is executed after the surrounding function returns. Defer is commonly used to simplify functions that perform various clean-up actions.
The defer expression saves a function call in the list, and the call in the list is executed when the function "back" of the package defer. Defer are usually used to clean up the finishing touches.
注意:这里的返回加了引号,原因如下
2 Implementing Logic
参考 雨痕大神的读书笔记(https://github.com/qyuhen/book)源码第20章
Broadly expressed as:
Step 1: In place of the defer expression, Runtime.deferproc (size int32, fn *funcval) is called to save the delay call, note that the parameters of the deferred call are saved here
Step 2: Save the return value first at return
Step 3: Call Runtime.deferreturn in filo order, i.e. delay call
Step 4:ret Instructions
Therefore, return is not an atomic operation, and the function return value may not be the same as what you expected.
3 Tips for avoiding pits
1. The parameters of the defer are determined at the time of the Declaration, and first look at an example (production environment that is estimated to be spit-sprayed to death)
func calc(index string, a, b int) int { ret := a + b fmt.Println(index, a, b, ret) return ret}func main() { a := 1 b := 2 defer calc("1", a, calc("10", a, b)) a = 0 defer calc("2", a, calc("20", a, b)) b = 1}
The output is:
10 1 2 320 0 2 22 0 2 21 1 3 4
The reason is that the 3rd parameter of Defer calc ("1", A, Calc ("Ten", A, b) will be determined when the runtime.deferproc is called and will not be evaluated when the delay is invoked.
2. Famous and nameless return values
func namedReturn() (r int) { defer func() { r++ fmt.Println("defer in namedReturn : r = ", r) }() return}func unnamedReturn() int { var r int defer func() { r++ fmt.Println("defer in unnamedReturn : r = ", r) }() return r}func main() { fmt.Println("namedReturn : r = ", namedReturn()) fmt.Println("unnamedReturn : r = ", unnamedReturn())}
The output is:
defer in namedReturn : r = 1namedReturn : r = 1defer in unnamedReturn : r = 1unnamedReturn : r = 0
The reason is that return will save the returned value first, for the nameless return value, saved in a temporary object, defer is not visible to the temporary object, and for the well-known return value, it is saved in the named variable.
3. The delay parameter and the famous return value shading
func ShelteredReturn() (r int) { defer func(r int) { r++ fmt.Println("defer in ShelteredReturn : r = ", r) }(r) return 0}func main() { fmt.Println("ShelteredReturn : r = ", ShelteredReturn())}
The output is:
defer in ShelteredReturn : r = 1ShelteredReturn : r = 0
Although R is a well-known return value, R in defer func (r int) is a formal parameter, and the return value of Shelteredreturn is not the same.
Reference documents
[1]. http://lib.csdn.net/article/go/33950
[2]. https://blog.golang.org/defer-panic-and-recover
[3]. https://my.oschina.net/henrylee2cn/blog/505535
[4]. Https://github.com/qyuhen/book