官方文档中关于defer语句的解释:
defer语句延迟执行一个函数,该函数被推迟到当包含它的程序返回时(包含它的函数 执行了return语句/运行到函数结尾自动返回/对应的goroutine panic)执行。
每次defer语句执行时,defer修饰的函数的返回值和参数取值会照常进行计算和保存,但是该函数不会执行。等到上一级函数返回前,会按照defer的声明顺序倒序执行全部defer的函数。defer的函数的任何返回值都会被丢弃。
如果一个defer的函数值为nil,则这个defer的函数会在函数执行时panic(异常),而不会在defer语句执行时panic,例如:
func test() { f := func(){ ("Test") } defer f() f = nil // 这里将函数的“值”设为nil,此时再尝试执行这个函数的时候 defer f() defer ("Test1") }
func main() { test() } |
执行结果:
Test1 Test panic: runtime error: invalid memory address or nil pointer dereference [signal 0xc0000005 code=0x0 addr=0x0 pc=0x451668]
goroutine 1 [running]: panic(0x49aaa0, 0xc042004090) D:/Program Files/Go/src/runtime/:500 +0x1af () D:/Programming/GoWork/:28 +0xfc () D:/Programming/GoWork/:31 +0x1b |
可以看到,第一个Test1正常输出了,说明设置f = nil后,defer f()并未直接panic,而是在test()返回之前,倒序执行到第二次f()的时候,抛出异常。同时Test也输出出来了,说明defer的方法在会在panic之前执行,不会因为panic了而停止执行,对比测试:
func test() { f := func(){ ("Test") } f() f = nil f() ("Test1") }
func main() { test() } |
执行结果:
Test panic: runtime error: invalid memory address or nil pointer dereference [signal 0xc0000005 code=0x0 addr=0x0 pc=0x40107a]
goroutine 1 [running]: panic(0x49aa20, 0xc042004090) D:/Program Files/Go/src/runtime/:500 +0x1af () D:/Programming/GoWork/:26 +0x3a () D:/Programming/GoWork/:31 +0x1b exit status 2 |
可以看到Test1并未输出,原因是在执行("Test1")之前test()已经panic了。
插播一条panic的处理方法:
通过内置方法recover()可以捕获panic,recover()方法有一个返回值,如果recover()捕获到panic,则返回panic对象,否则返回nil。下面是官方文档中的一个recover()的例子,封装了一个方法来捕获panic(类似于try…catch…):
func test() { f := func(){ ("Test") } f() f = nil f() ("Test1") }
func safeFunc(target func()) { defer func() { if x := recover(); x != nil { ("Runtime panic: ", x) } } () target() }
func main() { safeFunc(test) } |
执行结果:
Test Runtime panic: runtime error: invalid memory address or nil pointer dereference |
可以使用panic()函数人工抛出一个panic:
panic("Error Message")
回到defer的用法,下面举了几个例子来说明defer的用法:
示例1:
func main() { for i := 0; i < 3; i++ { defer (i) } } |
输出:2 1 0
上面的代码等价于:
func main() { defer (0) // 每次defer语句执行时,defer修饰的函数的返回值和参数取值会照常进行计算和保存 defer (1) // 同理 defer (2) // 同理 } |
即:
func main() { (2) (1) (0) } |
示例2:
func main() { for i := 0; i < 3; i++ { defer func() { (i) } () } } |
输出:
3 3 3
上面的代码等价于:
func main() { i := 0 defer func() { (i) } () // defer修饰的函数是闭包函数,而非里面的fmt语句,故里面的参数不变 i++ // i = 1 defer func() { (i) } () i++ // i = 2 defer func() { (i) } () i++ // i = 3 } |
即:
func main() { i := 0 i++ i++ i++ func() { (i) } () func() { (i) } () func() { (i) } () } |
示例3:
type demo1 struct { name string } func (t * demo1) close(){ (," closed"); } func main(){ ts:=[]demo1{{"a"},{"b"},{"c"}} for _,t := range ts{ defer () } } |
输出:
c closed
c closed
c closed
上面的代码(main部分)等价于:
func main() { ts := demo1{{"a"}, {"b"}, {"c"}} t = ts[0] defer () t = ts[1] defer () t = ts[2] defer () } |
即:
func main() { ts := demo1{{"a"}, {"b"}, {"c"}} t = ts[0] t = ts[1] t = ts[2] () () () } |
示例4:
修改一下示例3:
type demo1 struct { name string } func (t * demo1) close(){ (," closed"); } func close(t demo1){ () } func main(){ ts:=[]demo1{{"a"},{"b"},{"c"}} for _,t := range ts{ defer close(t) } } |
输出:
c closed
b closed
a closed
上面的代码等价于:
func main() { ts:=[]Test{{"a"},{"b"},{"c"}} t = ts[0] Close(ts[0]) // 与示例1原理相同 t = ts[1] Close(ts[1]) t = ts[2] Close(ts[2]) } |
下面的几个例子会用到return与defer的关系,return语句其实并不具有原子性,return语句的拆分:
return val
等价于:
real_return_val = val
// refer statements
return
示例5:
func test() int { var i int defer func() { i++ ("[1]", i) } () defer func() { i++ ("[2]", i) } () return i } func main() { ("[3]", test()) } |
输出:
[2] 1
[1] 2
[3] 0
上面的代码(test部分)等价于:
func test() int { var i int i = 0 ret := i // ret = 0 i++ ("[2]", i) // [2] 1 i++ ("[1]", i) // [1] 2 return ret // ret = 0 } |
示例6:
func test() (i int) { defer func() { i++ ("[1]", i) }() defer func() { i++ ("[2]", i) }() return i } func main() { ("[3]", test()) } |
输出:
[2] 1
[1] 2
[3] 2
上面的代码(test部分)等价于:
func test() (i int) { i = 0 i++ ("[2]", i) // [2] 1 i++ ("[1]", i) // [1] 2 return i // i = 2 } |
示例7:
func f() (result int) { defer func() { result++ }() return 0 } func main() { (f()) } |
输出:
1
上面的代码(f部分)等价于:
func f() (result int) { result = 0 func() { result++ } // result = 1 return } |
示例8:
func f() (r int) { t := 5 defer func() { t = t + 5 }() return t } func main() { (f()) } |
输出:
5
上面的代码(f部分)等价于:
func f() (r int) { t := 5 r = t func() { t = t + 5 }() return } |
示例9:
func f() (r int) { defer func(r int) { r = r + 5 (r) }(r) r++ return 1 } func main() { (f()) } |
输出:
5
1
上面的代码(f部分)等价于:
func f() (r int) { r++ r = 1 func(r int) { r = r + 5 (r) // 5 }(0) return } |