defer的实现原理与特性
defer 的实现原理是,将defer函数直接插入到函数末尾,将defer函数在当前函数内展开并直接调用
defer特性:
- 延迟特性:defer后的函数不会立即执行,而是延迟到函数结束后执行
参数预计算:defer后的函数的参数会立即求值,并固定下来,不会等到函数执行的时候再将参数传递到defer中
比如:
import "fmt" func main() { a := 1 defer func(a int) { fmt.Println(a) }(a +1) a = 100 }
会在执行到该defer的时候,计算a+1=2,然后把2当作参数固定下来,最后在函数返回前,执行defer函数内的语句,所以输出的是:2
执行顺序:按先进后出的顺序执行defer函数
比如:
import "fmt" func main() { defer func() { fmt.Println(111) }() defer func() { fmt.Println(222) }() defer func() { fmt.Println(333) }() defer func() { fmt.Println(444) }() }
输出为:
444 333 222 111
返回值陷阱:
return包含了下面几步:将返回值保存在栈上-》执行defer函数-〉函数返回
比如:
func deferReturn1() (r int) { defer func() { g = 200 }() return g } func deferReturn2() (r int) { r = g defer func() { r = 200 }() return r } func TestDeferReturn(t *testing.T) { t.Log(deferReturn1()) t.Log(deferReturn2()) } //输出 index_test.go:65: 100 index_test.go:66: 200
deferReturn1中,先计算了返回值并保存在栈上,此时r=100,再执行defer将g=200,实际返回的r则还是100
deferReturn2中,先将r=g,计算了返回值保存在栈上,此时r=100,再执行defer将r=200,最终返回的r为200
其他特点:
- panic之后的defer不会被执行
- panic没有recover时,抛出的panic到当前的grouting最上层函数时,最上层函数直接终止
- 当panic被捕获之后,当前gorouting上层函数正常执行
在panic之前定义的defer,会在panic之前执行
func TestDefer(t *testing.T) { defer func() { fmt.Println("c") }() panic("b") fmt.Println("TestDefer") } //输出 c --- FAIL: TestDefer (0.00s) panic: b [recovered] panic: b