天天看点

go语言defer、panic、recover

     ~~~~     作为一个初学者,看到新的东西,感觉记下来。

     ~~~~     defer,就是在退出所处的函数时,调用后面带的函数,defer后面只能跟函数调用。

     ~~~~     直接上例子:

package main

import (
	"fmt"
)
func printf_defer(_val int){
	fmt.Println("printf_defer val = ", _val)
}
func test1(){
	fmt.Println("------------------test1 start------------------")
	var i_defer_num int = 0
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(0)
	i_defer_num++
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(1)
	i_defer_num++
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(2)
	i_defer_num++
	fmt.Println("------------------test1 finish------------------")
}
func test2(){
	fmt.Println("------------------test2 start------------------")
	var i_defer_num int = 0
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(i_defer_num)
	i_defer_num++
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(i_defer_num)
	i_defer_num++
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(i_defer_num)
	i_defer_num++
	fmt.Println("------------------test2 finish------------------")
}
func main(){
	test1()
	test2()
}
           

     ~~~~     下面是直接结果:

[email protected]-F4U0002:/mnt/f/go/gopath/test/test2/test1$ go run main.go
------------------test2 start------------------
------------------ 0 ------------------
------------------ 1 ------------------
------------------ 2 ------------------
------------------test2 finish------------------
printf_defer val =  2
printf_defer val =  1
printf_defer val =  0
------------------test1 start------------------
------------------ 0 ------------------
------------------ 1 ------------------
------------------ 2 ------------------
------------------test1 finish------------------
printf_defer val =  2
printf_defer val =  1
printf_defer val =  0
[email protected]-F4U0002:/mnt/f/go/gopath/test/test2/test1$
           

     ~~~~     看上面的例子,我们可以发现两个特点,第一defer在所处函数域结束的时候,会调用defer后面的函数,第二,defer保存函数的方式是栈的方式,最后一个调用defer的函数,在结束的时候,第一个调用。

     ~~~~     panic,是用来表示非常严重的不可恢复的错误的,可以理解为抛出异常,带一个参数,会打印出所带的参数。

     ~~~~     例子:

package main

import (
	"fmt"
)
func printf_defer(_val int){
	fmt.Println("printf_defer val = ", _val)
}
func test1(){
	fmt.Println("------------------test1 start------------------")
	var i_defer_num int = 0
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(i_defer_num)
	i_defer_num++
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(i_defer_num)
	i_defer_num++
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(i_defer_num)
	i_defer_num++
	if(i_defer_num > 0){
		panic(1)
	}	
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(i_defer_num)
	i_defer_num++
	fmt.Println("------------------test1 finish------------------")
}
func main(){
	test1()
}
           

     ~~~~     运行结果:

[email protected]:/mnt/f/go/gopath/test/test2/test2$ go run main.go
------------------test1 start------------------
------------------ 0 ------------------
------------------ 1 ------------------
------------------ 2 ------------------
printf_defer val =  2
printf_defer val =  1
printf_defer val =  0
panic: 1

goroutine 1 [running]:
main.test1()
        /mnt/f/go/gopath/test/test2/test2/main.go:22 +0x31c
main.main()
        /mnt/f/go/gopath/test/test2/test2/main.go:30 +0x20
exit status 2
[email protected]:/mnt/f/go/gopath/test/test2/test2$
           

     ~~~~     可以发现,在panic之前的defer都执行了,而在panic之后的defer没有执行,然后提示的错误,之处的出错的代码函数,而且列出了调用的地方,而且这个时候,我们的程序直接崩溃了,没有在运行下去了。既然是异常,那么就有捕获的办法,那就是recover。

     ~~~~     recover,在panic之后,可以捕获到当前的panic(如果有的话),被捕获到的panic就不会向上传递了,这样程序就不会奔溃了,在panic执行之后,会先调用在panic之前的defer,然后在程序奔溃,而我们只要在panic执行之后的defer中执行recover就可以处理掉panic,注意在recover处理了panic之后,程序不会回到panic的位置,而是会继续defer之后退出函数,返回上一级。

     ~~~~     例子:

package main

import (
	"fmt"
)
func printf_defer(_val int){
	fmt.Println("printf_defer val = ", _val)
}
func test1(){
	defer func(){
		fmt.Println("recovery start")
        if err := recover(); err != nil {
			fmt.Println("recovery panic")
            fmt.Println(err)
        }
        fmt.Println("recovery finish")
	}()

	fmt.Println("------------------test1 start------------------")
	var i_defer_num int = 0
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(i_defer_num)
	i_defer_num++
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(i_defer_num)
	i_defer_num++
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(i_defer_num)
	i_defer_num++
	if(i_defer_num > 0){
		panic(1)
	}	
	fmt.Println("------------------", i_defer_num, "------------------")
	defer printf_defer(i_defer_num)
	i_defer_num++
	fmt.Println("------------------test1 finish------------------")
}
func main(){
	fmt.Println("------------------main start------------------")
	test1()
	fmt.Println("------------------main finish------------------")
}
           

     ~~~~     

[email protected]:/mnt/f/go/gopath/test/test2/test3$ go run main.go
------------------main start------------------
------------------test1 start------------------
------------------ 0 ------------------
------------------ 1 ------------------
------------------ 2 ------------------
printf_defer val =  2
printf_defer val =  1
printf_defer val =  0
recovery start
recovery panic
1
recovery finish
------------------main finish------------------
[email protected]:/mnt/f/go/gopath/test/test2/test3$
           

     ~~~~     很好我们可以看见panic被处理掉了,程序直接到了上一级,程序运行没有被中断。