根据代码实例运行结果来总结
说明:定义一个函数,有多个defer (用于判断多个defer执行顺序),有panic和 return (判断与defer对比执行顺序)
一、函数中有panic
package main
import "fmt"
func main() {
fmt.Println("main func start")
defer func(){
fmt.Println("main defer func 1")
}()
s := test()
fmt.Println("main get test() return:",s)
}
func test() (str string) {
defer func() {
//捕获panic
if msg := recover(); msg != nil {
fmt.Println("test defer func1 捕获到错误:",msg)
}
str = "bbb"
}()
defer func(){
fmt.Println("test defer func2")
}()
defer func(){
fmt.Println("test defer func3")
}()
str = "aaa"
fmt.Println("panic抛出前")
panic("test painc")
fmt.Println("panic抛出后")
return str
}
执行结果:
根据执行结果可知道:
函数内多个defer执行顺序是 先入后出(即入栈)
panic 先于defer执行,不然defer函数内捕获不到错误
panic执行后 后续逻辑及return 没有执行
二、然后将代码中 panic注释掉再执行
执行结果:
根据执行结果可知:
defer中可以修改返回值,注意:前提是函数的返回值不是匿名的
三、函数返回的是匿名参数
package main
import "fmt"
func main() {
fmt.Println("main func start")
defer func(){
fmt.Println("main defer func 1")
}()
s := test()
fmt.Println("main get test() return:",s)
}
func test() (string) {
str := "aaa"
defer func() {
//捕获panic
if msg := recover(); msg != nil {
fmt.Println("test defer func1 捕获到错误:",msg)
}
str = "ccc"
}()
defer func(){
fmt.Println("test defer func2")
}()
defer func(){
fmt.Println("test defer func3")
}()
fmt.Println("panic抛出前")
panic("test painc")
fmt.Println("panic抛出后")
return str
}
执行结果:
然后注释掉panic执行结果
根据执行结果:
函数返回参数是匿名的 defer无法修改
函数中有panic 匿名的返回值是零值,因为return赋值得不到执行,defer又修改不到返回值
***注意(非常重要):这里需要提到的是函数的return是分为两个步骤:return最先执行,先将结果写入返回值中(即赋值);接着defer开始执行一些收尾工作;最后函数携带当前返回值退出(即返回值)。
有panic的时候,return第一步没有执行到,无法将结果写入返回值中,那么函数退出前则只能返回参数类型的零值
四、总结:
函数中有多个defer,则是按先进后出(压栈)执行
panic先于defer执行,所以能通过defer中去捕获panic错误
defer可以修改函数的返回参数,前提是函数返回的参数不是匿名的
函数执行出现panic那么return得不到执行,如果返回参数是匿名的,那么函数最终返回的是返回参数的类型零值,如果返回参数不是匿名的,在panic前有对返回参数赋值,那么就能返回这个值,如果defer有对其修改,那么返回值则是defer修改的。