企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
## panic ~~~ 1、内置函数 2、假如函数F中书写了panic语句,会终止其后要执行的代码,在panic所在函数F内如果存在要执行的defer函数列表,按照defer的逆序执行 3、返回函数F的调用者G,在G中,调用函数F语句之后的代码不会执行,假如函数G中存在要执行的defer函数列表,按照defer的逆序执行 4、直到goroutine整个退出,并报告错误 ~~~ ## recover ~~~ 1、内置函数 2、用来控制一个goroutine的panicking行为,捕获panic,从而影响应用的行为 3、一般的调用建议 a). 在defer函数中,通过recever来终止一个goroutine的panicking过程,从而恢复正常代码的执行 b). 可以获取通过panic传递的error ~~~ 注意: ~~~ 1.利用recover处理panic指令,defer 必须放在 panic 之前定义,另外 recover 只有在 defer 调用的函数中才有效。否则当panic时,recover无法捕获到panic,无法防止panic扩散。 2.recover 处理异常后,逻辑并不会恢复到 panic 那个点去,函数跑到 defer 之后的那个点。 3.多个 defer 会形成 defer 栈,后定义的 defer 语句会被最先调用。 ~~~ ## panic vs recover panic和recover与其他语言中的try-catch-finally语句类似,只不过一般我们很少使用panic和recover; 需要注意的是,你应该尽可能地使用错误,而不是使用 panic 和 recover。只有当程序不能继续运行的时候,才应该使用 panic 和 recover 机制 * panic用于不可恢复的错误 * panic退出前会执行defer指定的内容 使用场景: 1. **发生了一个不能恢复的错误,此时程序不能继续运行**。 一个例子就是 web 服务器无法绑定所要求的端口。在这种情况下,就应该使用 panic,因为如果不能绑定端口,啥也做不了。 2. **发生了一个编程上的错误**。 假如我们有一个接收指针参数的方法,而其他人使用`nil`作为参数调用了它。在这种情况下,我们可以使用 panic,因为这是一个编程错误:用`nil`参数调用了一个只能接收合法指针的方法 --- ***注意:当函数发生 panic 时,它会终止运行,在执行完所有的延迟函数后,程序控制返回到该函数的调用方。这样的过程会一直持续下去,直到当前协程的所有函数都返回退出,然后程序会打印出 panic 信息,接着打印出堆栈跟踪,最后程序终止*** ### 2.panic vs. os.Exit * os.Exit退出时不会调用defer指定的函数 * os.Exit退出时不输出当前调用栈信息 ### 3.recover `recover`是一个内建函数,用于重新获得 panic 协程的控制 `recover`函数的标签如下所示: ~~~go func recover() interface{} ~~~ 只有在延迟函数的内部,调用`recover`才有用。在延迟函数内调用`recover`,可以取到`panic`的错误信息,并且停止 panic 续发事件(Panicking Sequence),程序运行恢复正常。如果在延迟函数的外部调用`recover`,就不能停止 panic 续发事件 ~~~ defer func() { if err := recover(); err != nil{ // 恢复错误 } }() ~~~ ### 4.panic vs. recover vs. Goroutine 只有在相同的Goroutine中调用 recover 才管用;`recover`不能恢复一个不同协程的 panic; 运行时错误(如数组越界)也会导致 panic。这等价于调用了内置函数`panic`,其参数由接口类型给出 `runtime.Error`接口的定义如下: ~~~go type Error interface { error // RuntimeError is a no-op function but // serves to distinguish types that are run time // errors from ordinary errors: a type is a // run time error if it has a RuntimeError method. RuntimeError() } ~~~ 当我们恢复panic时,我们就释放了它的堆栈跟踪,如果需要打印堆栈使用: ``` debug.PrintStack() ``` ### Go类try-catch语法 ~~~ func Try(fun func(), handler func(interface{})) { defer func() { if err := recover(); err != nil { handler(err) } }() fun() } ~~~