Go语言中,函数内可以依次包含多个defer语句,在函数结束时,defer语句会逆序执行
| func main() { |
| fmt.Println("start...") |
| defer fmt.Println(1) |
| defer fmt.Println(2) |
| defer fmt.Println(3) |
| fmt.Println("end...") |
| } |
输出
由于defer
语句延迟调用的特性,所以defer
语句能非常方便的处理资源释放问题。比如:资源清理、文件关闭、解锁及记录时间等。
在Go语言的函数中return
语句在底层并不是原子操作,它分为给返回值赋值和RET指令两步。而defer
语句执行的时机就在返回值赋值操作后,RET指令执行前。具体如下图所示:
下述代码运行结果是???
| package main |
| |
| import "fmt" |
| |
| |
| func f1() int { |
| x := 5 |
| defer func() { |
| x++ |
| fmt.Println("f1===>",x) |
| }() |
| return x |
| } |
| func f2() (y int) { |
| x := 5 |
| defer func() { |
| x++ |
| |
| fmt.Println("f2===>",x) |
| }() |
| return x |
| } |
| func f3() (x int) { |
| defer func(x int) { |
| x++ |
| fmt.Println("f3===>",x) |
| |
| }(x) |
| return 5 |
| } |
| func f4() (x int) { |
| defer func() { |
| x++ |
| fmt.Println("f4===>",x) |
| |
| }() |
| return 5 |
| } |
| |
| func main() { |
| fmt.Println(f1()) |
| fmt.Println(f2()) |
| fmt.Println(f3()) |
| fmt.Println(f4()) |
| } |
下述代码输出结果为???提示:在defer注册要延迟执行的函数时,该函数所有的参数的值都会被确定下来
| func calc(index string, a, b int) int { |
| ret := a + b |
| fmt.Println(index, a, b, ret) |
| return ret |
| } |
| |
| func main() { |
| x := 1 |
| y := 2 |
| defer calc("AA", x, calc("A", x, y)) |
| x = 10 |
| defer calc("BB", x, calc("B", x, y)) |
| y = 20 |
| } |
panic/recover
Go语言使用panic/recover
模式来处理错误。 panic
可以在任何地方引发,但recover
只有在defer
调用的函数中有效。 首先来看一个例子:
| func funcA() { |
| fmt.Println("func A") |
| } |
| |
| func funcB() { |
| panic("panic in B") |
| } |
| |
| func funcC() { |
| fmt.Println("func C") |
| } |
| func main() { |
| funcA() |
| funcB() |
| funcC() |
| } |
输出:
| func A |
| panic: panic in B |
| |
| goroutine 1 [running]: |
| main.funcB(...) |
| .../code/func/main.go:12 |
| main.main() |
| .../code/func/main.go:20 +0x98 |
程序运行期间funcB
中引发了panic
导致程序崩溃,异常退出了。这个时候我们就可以通过recover
将程序恢复回来,继续往后执行。
| func funcA() { |
| fmt.Println("func A") |
| } |
| |
| func funcB() { |
| defer func() { |
| err := recover() |
| |
| if err != nil { |
| fmt.Println("recover in B") |
| } |
| }() |
| panic("panic in B") |
| } |
| |
| func funcC() { |
| fmt.Println("func C") |
| } |
| func main() { |
| funcA() |
| funcB() |
| funcC() |
| } |
注意:
recover()
必须搭配defer
使用。
defer
一定要在可能引发panic
的语句之前定义。