defer执行的原则
- defer延迟函数总是在异常panic或者正常return前返回;
- defer执行顺序按照先入后出的原则,即先入栈的最后执行;但是会先把参数压入栈,具体执行会在函数结束前
- 当defer函数中存在函数时会先执行里面的函数;
- defer函数调用的参数当存在闭包时,会从外面拿取该参数的最新的值;
- defer常常与recover一同使用;用来做异常捕捉后的延迟执行;从而将异常给转换为错误error;
看几个案例:
案例1:
func main() {
i := 10
defer fmt.Printf("defer i=%d", i)
i = 100
fmt.Println(i)
}
/*
output:
100
defer i=10
*/
用到原则1、2
案例2:
func calc(x,y int )int{
res:=x+y
fmt.Println(x,y,res)
return res
}
func main(){
a:=10
b:=20
defer calc(a,calc(a,b))
a=100
defer calc(a,calc(a,b))
a=1000
}
//output:
//10 20 30
//100 20 120
//100 120 220
//10 30 40
使用到原则1,2,3
案例3:
func calc(x,y int )int{
res:=x+y
fmt.Println(x,y,res)
return res
}
func main(){
a:=10
b:=20
defer func(i int) {
calc(a,calc(a,b))
fmt.Println(i)
}(1000)
a=100
}
//闭包的原理:a会从函数外面找最新的那个值,这个区别于main2中的压栈执行(先将a传进去,等待执行);
//output:
//100 20 120
//100 120 220
//1000
使用到原则1,2,3,4
案例4:
func divi(x,y int) (z int,err error){
defer func() {
if e := recover();e!=nil{
err =e.(error)
}
}()
z = x / y
return z ,nil
}
/*
input:divi(1,0)
output:
0 runtime error: integer divide by zero
*/
使用到原则1,2,3,5
案例5:
func main() {
println(DeferFunc1(1))
println(DeferFunc2(1))
println(DeferFunc3(1))
}
func DeferFunc1(i int)(t int) {
t = i
defer func() {
t += 3
}()
return t
}
func DeferFunc2(i int)int {
t := i
defer func() {
t += 3
}()
return t
}
func DeferFunc3(i int)(t int) {
defer func() {
t += i
}()
return 2
}
/*
output:
4 1 3
*/
使用到原则1;
此外对于返回值如果在返回参数中声明了变量,那们他就是全局的;
按照此原则,DeferFunc1;t被全局声明,在返回前调用defer,返回4;DeferFunc2中
t在函数内部声明,defer相当于闭包调用了外面的t,相当于赋值黏贴改的不是指针;所以返回的是1;DeferFunc3中t全局声明了 ,此外return 2相当于给t赋值为2;之后再调用defer,所以返回的是3
案例6:
func main() {
defer func() {
if err:=recover();err!=nil{
fmt.Println("++++")
f:=err.(func()string)
fmt.Println(err,f(),reflect.TypeOf(err).Kind().String())
}else {
fmt.Println("fatal")
}
}()
defer func() {
fmt.Println("-----")
panic (func()string {
return "defer panic"
})
}()
panic("panic")
}
/*
-----
++++
0x49abd0 defer panic func
*/
panic仅有最后一个可以被revover捕获
触发panic(“panic”)后顺序执行defer,但是defer中还有一个panic,所以覆盖了之前的panic(“panic”)