ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

go语言-异常处理机制-panic和recover的使用和原理

2020-05-13 14:57:11  阅读:381  来源: 互联网

标签:defer PHP 异常 捕获 go recover panic


背景:

Go语言追求简洁优雅,所以,Go语言不支持传统的 try…catch…finally 这种异常,因为Go语言的设计者们认为,将异常与控制结构混在一起会很容易使得代码变得混乱。因为开发者很容易滥用异常,甚至一个小小的错误都抛出一个异常。在Go语言中,使用多值返回来返回错误。不要用异常代替错误,更不要用来控制流程。在极个别的情况下(比如除数为0了),才使用Go中引入的Exception处理:defer, panic, recover。

panic:

1、内建函数
2、假如函数F中书写了panic语句,会终止其后要执行的代码,在panic所在函数F内如果存在要执行的defer函数列表,按照defer的逆序执行
3、返回函数F的调用者G,在G中,调用函数F语句之后的代码不会执行,假如函数G中存在要执行的defer函数列表,按照defer的逆序执行,这里的defer 有点类似 try-catch-finally 中的 finally
4、直到goroutine整个退出,并报告错误

recover:

1、内建函数
2、用来控制一个goroutine的panicking行为,捕获panic,从而影响应用的行为
3、一般的调用建议
  a). 在defer函数中,通过recever来终止一个gojroutine的panicking过程,从而恢复正常代码的执行
  b). 可以获取通过panic传递的error

简单来讲:go中可以抛出一个panic的异常,然后在defer中通过recover捕获这个异常,然后正常处理。

 

示例:

package main

import (
    "fmt"
)

func main() {
    GO()
    PHP()
    PYTHON()
}
//Go没有异常机制,但有panic/recover模式来处理错误
//Panic可以在任何地方引发,但recover只有在defer调用的函数中有效
func GO() {
    fmt.Println("我是GO,现在没有发生异常,我是正常执行的。")
}

func PHP() {
    // panic一般会导致程序挂掉(除非recover)  然后Go运行时会打印出调用栈
    //但是,关键的一点是,即使函数执行的时候panic了,函数不往下走了,运行时并不是立刻向上传递panic,而是到defer那,等defer的东西都跑完了,panic再向上传递。所以这时候 defer 有点类似 try-catch-finally 中的 finally。panic就是这么简单。抛出个真正意义上的异常。
    panic("我是PHP,我要抛出一个异常了,等下defer会通过recover捕获这个异常,然后正常处理,使后续程序正常运行。")
    fmt.Println("我是PHP里panic后面要打印出的内容。")
}

func PYTHON() {
    fmt.Println("我是PYTHON,没有defer来recover捕获panic的异常,我是不会被正常执行的。")
}

输出:(注意:此时的PYTHON 没有输出打印出内容,后面打印的是GO的调用栈)

goroutine 1 [running]:
main.PHP(...)
/Users/jordan/GolandProjects/LearnGoProject/go-new-course/day05-20200510/123445.go:22
main.main()
/Users/jordan/GolandProjects/LearnGoProject/go-new-course/day05-20200510/123445.go:9 +0x96
exit status 2

package main

import (
    "fmt"
)

func main() {
    GO()
    PHP()
    PYTHON()
}//Go没有异常机制,但有panic/recover模式来处理错误
//Panic可以在任何地方引发,但recover只有在defer调用的函数中有效
func GO() {
    fmt.Println("我是GO,现在没有发生异常,我是正常执行的。")
}

func PHP() {
    // 必须要先声明defer,否则不能捕获到panic异常,也就是说要先注册函数,后面有异常了,才可以调用
    defer func() {
        if err := recover(); err != nil {
            fmt.Println("终于捕获到了panic产生的异常:", err) // 这里的err其实就是panic传入的内容
            fmt.Println("我是defer里的匿名函数,我捕获到panic的异常了,我要recover,恢复过来了。")
        }
    }() //注意这个()就是调用该匿名函数的,不写会报expression in defer must be function call

    // panic一般会导致程序挂掉(除非recover)  然后Go运行时会打印出调用栈
    //但是,关键的一点是,即使函数执行的时候panic了,函数不往下走了,运行时并不是立刻向上传递panic,而是到defer那,等defer的东西都跑完了,panic再向上传递。所以这时候 defer 有点类似 try-catch-finally 中的 finally。panic就是这么简单。抛出个真正意义上的异常。
    panic("我是PHP,我要抛出一个异常了,等下defer会通过recover捕获这个异常,捕获到我时,在PHP里是不会输出的,会在defer里被捕获输出,然后正常处理,使后续程序正常运行。但是注意的是,在PHP函数里,排在panic后面的代码也不会执行的。")
    fmt.Println("我是PHP里panic后面要打印出的内容。但是我是永远也打印不出来了。因为逻辑并不会恢复到panic那个点去,函数还是会在defer之后返回,也就是说执行到defer后,程序直接返回到main()里,接下来开始执行PYTHON()")
}

func PYTHON() {
    fmt.Println("我是PYTHON,没有defer来recover捕获panic的异常,我是不会被正常执行的。")
}

输出:
我是GO,现在没有发生异常,我是正常执行的。
终于捕获到了panic产生的异常: 我是PHP,我要抛出一个异常了,等下defer会通过recover捕获这个异常,捕获到我时,在PHP里是不会输出的,会在defer里被捕获输出,然后正常处理,使后续程序正常运行。但是注意的是,在PHP函数里,排在panic后面的代码也不会执行的。
我是defer里的匿名函数,我捕获到panic的异常了,我要recover,恢复过来了。
我是PYTHON,没有defer来recover捕获panic的异常,我是不会被正常执行的。



参考:https://blog.csdn.net/qq_27682041/article/details/78786689

标签:defer,PHP,异常,捕获,go,recover,panic
来源: https://www.cnblogs.com/malukang/p/12882260.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有