defer 的一些用法和猜测
如果执行过程中发生 panic,defer函数 recover() != nil
的情况下,未命名的返回值的函数会返回什么呢?
之前并没有没有想过这个问题,猜想应该是返回该类型的默认值,试了一下果然如此。
func fooA() float64 { defer func() { if err := recover(); err != nil { } }() *(*float64)(nil) = 0.1 // panic return 1.0 }
fooA()
返回0。
那么如果 defer 函数返回值和上层函数一致,会不会替换掉返回值呢?(
会就有鬼了
)
func fooB() float64 { defer func() float64 { if err := recover(); err != nil { return 1.1 } else { return 1.2 } }() *(*float64)(nil) = 0.1 return 1.0 }
fooB()
返回0。
事实上,如果要在 defer 中修改函数的返回值,目前我只知道一种办法:使用命名的返回参数:
func fooC() (x float64) { defer func() { if err := recover(); err != nil { x = 1.1 return } }() *(*float64)(nil) = 0.1 return 1.0 }
fooC()
返回1.1。
https://golang.org/ref/spec#Defer_statements
核心的说明我认为是这一句话:
That is, if the surrounding function returns through an explicit return statement
, deferred functions are executed after
any result parameters are set by that return statement but before
the function returns to its caller.
搜索信息的过程中发现这样的一篇文章: 一道考察defer与命名返回值的题目
DeferFunc1 和 DeferFunc3 还比较好解释,对于文中的DeferFunc2,强行猜测了一下:
func dfB(i int) int { // return anonymous int,we assume it named `noNameI`。 t := i // Local var t is assigned to 1. defer func() { // Here noNameI is 2, t is 1. t += i // t is 3, noNameI unchanged. }() return 2 // noNameI is assigned to 2. }
dfB()
返回 2,为什么呢?
代码 return 2
的时候应该是将2赋值给了匿名的返回值变量,因此 defer 函数中的对本地变量的 t 的操作便无关紧要。