~~~~ 作为一个初学者,看到新的东西,感觉记下来。
~~~~ 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被处理掉了,程序直接到了上一级,程序运行没有被中断。