原文地址:嗨客网
Go 语言 中的 panic 的作用就是抛出一条错误信息,从它的参数类型可以看到它可以抛出任意类型的错误信息。在函数执行过程中的某处调用了 panic,则立即抛出一个错误信息,同时函数的正常执行流程终止,但是该函数中 panic 之前定义的 defer 语句将被依次执行。之后该 goroutine 立即停止执行。
recover() 用于将 panic 的信息捕捉。recover 必须定义在 panic 之前的 defer 语句中。在这种情况下,当 panic 被触发时,该 goroutine 不会简单的终止,而是会执行在它之前定义的 defer 语句。
defer func() {
if err := recover(); err != nil {
fmt.Println("Panic recover, Err =", err, "Stack =", string(debug.Stack()))
}
}()
当发生异常时,我们使用了 recover 恢复,并打印了错误信息和堆栈信息。
如果在一个函数中,遇到了 panic,并且没有 recover,那么程序直接终止
package main
import (
"fmt"
)
func main() {
fmt.Println("嗨客网(www.haicoder.net)")
var hMap map[string]string
hMap["name"] = "haicoder"
}
此时,我们运行程序,控制台输出如下:
我们给一个空 map 赋值,结果程序发生了 panic,因为,我们没有 recover,因此,程序异常终止了。
如果在一个函数中,遇到了 panic,并且有 recover,那么程序不会终止
package main
import (
"fmt"
)
func main() {
fmt.Println("嗨客网(www.haicoder.net)")
defer func() {
if err := recover(); err != nil {
fmt.Println("Panic recover, Err =", err)
}
}()
var hMap map[string]string
hMap["name"] = "haicoder"
fmt.Println("Over")
}
此时,我们运行程序,控制台输出如下:
这次,在函数里面,我们使用了 recover 捕获错误,我们看到,此时程序不再报错了,并且,异常下面的代码不会再继续执行了。
子函数 panic,并且有 recover,不影响主函数的执行
package main
import (
"fmt"
)
func main() {
fmt.Println("嗨客网(www.haicoder.net)")
fmt.Println(fun1(10, 5))
fmt.Println(fun1(10, 0))
fmt.Println(fun1(10, 2))
fmt.Println("Over")
}
func fun1(a, b int)int{
defer func() {
if err := recover(); err != nil {
fmt.Println("Panic recover, Err =", err)
}
}()
return a / b
}
此时,我们运行程序,控制台输出如下:
我们在子函数里面,发生了 panic,并且使用了 recover,此时在调用函数里面,调用子函数,并不影响主函数的执行。
子函数 panic,主函数 recover,程序不会终止执行
package main
import (
"fmt"
)
func main() {
fmt.Println("嗨客网(www.haicoder.net)")
defer func() {
if err := recover(); err != nil {
fmt.Println("Panic recover, Err =", err)
}
}()
fmt.Println(fun1(10, 5))
fmt.Println(fun1(10, 0))
fmt.Println(fun1(10, 2))
fmt.Println("Over")
}
func fun1(a, b int)int{
return a / b
}
此时,我们运行程序,控制台输出如下:
我们在子函数里面,发生了 panic,并且在主函数使用了 recover,此时程序不会终止执行。
子协程 panic,主函数 recover,程序会终止执行
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("嗨客网(www.haicoder.net)")
defer func() {
if err := recover(); err != nil {
fmt.Println("Panic recover, Err =", err)
}
}()
go fun1(10, 5)
go fun1(10, 0)
go fun1(10, 2)
fmt.Println("Over")
time.Sleep(10*time.Second)
}
func fun1(a, b int)int{
return a / b
}
此时,我们运行程序,控制台输出如下:
我们在子协程里面,发生了 panic,并且在主函数使用了 recover,此时程序会终止执行。
子协程 panic,子协程 recover,不影响主函数执行
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println("嗨客网(www.haicoder.net)")
go fun1(10, 5)
go fun1(10, 0)
go fun1(10, 2)
fmt.Println("Over")
time.Sleep(10*time.Second)
}
func fun1(a, b int)int{
defer func() {
if err := recover(); err != nil {
fmt.Println("Panic recover, Err =", err)
}
}()
return a / b
}
此时,我们运行程序,控制台输出如下:
在主函数里面,子协程发生了 panic,并且使用了 recover,不影响主函数的继续执行。
golang 中的 defer 的使用可以总结为,如果 panic 和 recover 发生在同一个协程,那么 recover 是可以捕获的,如果 panic 和 recover 发生在不同的协程,那么 recover 是不可以捕获的。
原文地址:嗨客网
更多文章,可以关注下方公众号:
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.