golang之defer、panic、recover
2018-02-27 22:10
881 查看
go中可以抛出一个panic的异常,然后在defer中通过recover捕获异常,然后生成终止函数(程序)
2.defer函数的执行按照后进先出 的顺序。
3.defer函数可以读取和分配返回函数的返回值(Deferred functions may read and assign to the returning function’s named return values)。
1.无名返回值的情况
2.有名返回值的情况
3.返回指针的情况
注意: recover之后,逻辑并不会恢复到panic那个点去,函数还是会在defer之后返回。
此处不做解释,如果不懂,返回查看前文描述的内容即可。
defer,panic and recover
defer介绍
defer语法介绍
1.defer函数的参数被计算在defer被声明的的时候。func a() { i := 0 defer fmt.Println(i) i++ return } //结果: 打印的i值为0,因为i值为0的时候,使用了defer关键字
2.defer函数的执行按照后进先出 的顺序。
func b() { for i := 0; i < 4; i++ { defer fmt.Print(i) } } //结果: “3210”,(后进先出的顺序,无需解释)
3.defer函数可以读取和分配返回函数的返回值(Deferred functions may read and assign to the returning function’s named return values)。
func c() (i int) { defer func() { i++ }() return 1 } //结果: 函数返回值为2 //原因:return 1会将函数返回值i赋值为1, 然后执行i++,所以返回值为2
//这里出一道结合了1,3两个用法的题。 func c() (i int) { defer func(i int) { i++ fmt.Println("i's value ", i) }(i) return 1 } //结果:函数的返回值为1,打印内容为“i's value 1" //原因:defer函数在定义的时候就确定参数的值
defer的执行次序
defer、return、返回值三者的执行逻辑应该是:return最先执行,return负责将结果写入返回值;接着defer开始执行一些收尾工作;最后函数携带当前返回值退出。1.无名返回值的情况
package main import ( "fmt" ) func main() { fmt.Println("return:", a()) // 打印结果为 return: 0 } func a() int { var i int defer func() { i++ fmt.Println("defer2:", i) // 打印结果为 defer: 2 }() defer func() { i++ fmt.Println("defer1:", i) // 打印结果为 defer: 1 }() return i } //原因:函数的返回值没有被提前声名,其值来自于其他变量的赋值,而defer中修改的也是其他变量,而非返回值本身,因此函数退出时返回值并没有被改变。
2.有名返回值的情况
package main import ( "fmt" ) func main() { fmt.Println("return:", b()) // 打印结果为 return: 2 } func b() (i int) { defer func() { i++ fmt.Println("defer2:", i) // 打印结果为 defer: 2 }() defer func() { i++ fmt.Println("defer1:", i) // 打印结果为 defer: 1 }() return i // 或者直接 return 效果相同 } //原因:函数的返回值被提前声名,也就意味着defer中是可以调用到真实返回值的,因此defer在return赋值返回值 i 之后,再一次地修改了 i 的值,最终函数退出后的返回值才会是defer修改过的值。
3.返回指针的情况
package main import ( "fmt" ) func main() { fmt.Println("c return:", *(c())) // 打印结果为 c return: 2 } func c() *int { var i int defer func() { i++ fmt.Println("c defer2:", i) // 打印结果为 c defer: 2 }() defer func() { i++ fmt.Println("c defer1:", i) // 打印结果为 c defer: 1 }() return &i } //原因:c()*int 的返回值是指针变量,那么在return将变量 i 的地址赋给返回值后,defer再次修改了 i 在内存中的实际值,因此函数退出时返回值虽然依旧是原来的指针地址,但是其指向的内存实际值已经被成功修改了。
panic
panic是用来表示非常严重的不可恢复的错误的。在Go语言中这是一个内置函数,接收一个interface{}类型的值作为参数。如果不使用recover,panic会导致程序直接挂掉。关键的一点是,在函数执行panic的时候,函数会首先执行defer定义的内容,在defer内容执行完之后,panic再向上传递。recover
recover也是一个Go语言的内置函数,用于再次恢复panic的goroutine。recover必须在defer函数中使用 。当正常执行的是时候,调用recover将会返回nil并且不会有任何其他影响;如果当前的goroutine是panic,调用recover将捕捉到panic传入的值并且再次正常执行。注意: recover之后,逻辑并不会恢复到panic那个点去,函数还是会在defer之后返回。
综合例子展示
package main import "fmt" func main() { f() fmt.Println("Returned normally from f.") } func f() { defer func() { if r := recover(); r != nil { fmt.Println("Recovered in f", r) } }() fmt.Println("Calling g.") g(0) fmt.Println("Returned normally from g.") } func g(i int) { if i > 3 { fmt.Println("Panicking!") panic(fmt.Sprintf("%v", i)) } defer fmt.Println("Defer in g", i) fmt.Println("Printing in g", i) g(i + 1) }
结果
Calling g. Printing in g 0 Printing in g 1 Printing in g 2 Printing in g 3 Panicking! Defer in g 3 Defer in g 2 Defer in g 1 Defer in g 0 Recovered in f 4 Returned normally from f.
此处不做解释,如果不懂,返回查看前文描述的内容即可。
参考资料
Golang中defer、return、返回值之间执行顺序的坑defer,panic and recover
相关文章推荐
- golang 函数-defer-recover-panic
- golang之defer,panic,recover用法
- golang学习的点点滴滴:异常处理 defer, panic, recover
- 【GoLang】panic defer recover 深入理解
- golang的defer,recover,panic用法
- golang中的defer panic recover
- golang 使用defer、panic、recover的问题
- Golang中的defer, panic, recover
- GO_05_2:Golang 中 panic、recover、defer 的用法
- Go-defer,panic,recover
- GO defer panic recover
- golang panic recover
- golang中recover和panic用法
- Go的异常处理 defer, panic, recover
- Golang 笔记 4 defer、error、panic
- golang中recover和panic用法
- golang中recover和panic用法
- Golang的panic和recover
- golang用panic和recover做业务流程中断的尝试
- Go的异常处理 defer, panic, recover<转载>