区分有恢复的恐慌和没有发生错误

  • 本文关键字:错误 恢复 go
  • 更新时间 :
  • 英文 :


我有以下代码:

package main
import (
"fmt"
)
func recoverFoo() {
if r := recover(); r != nil {
println("Recovered")
}
}
func foo() (int, error) {
defer recoverFoo()
panic("shit!")
}
func main() {
x, err := foo()
println("after foo x = " + fmt.Sprint(x))
if err != nil {
println("An error occured")
} else {
println("No error occured")
}
}

在这种情况下,我调用的是foo(实际上,我的函数foo调用的是第三方库,它有时会死机,但有时也会返回err(。如果它感到恐慌,我不能让它崩溃应用程序,但我需要知道出了什么问题,因为我必须在错误时写入本地存储。

在这种情况下,虽然从Foo返回的值x可以具有0的有效值。因此,恢复设置x和err为默认值(0和nil(并不能告诉我是否真的发生了错误。。。

我看到了两种可能的解决方案,(1(我将err和x封装到一个自定义的返回类型中,并假设如果为nil,则发生错误。(2( 我有第三个返回布尔值,指定没有发生恐慌(默认为false(

这是我在处理失误和从恐慌中恢复时所缺少的东西吗。我是新来的,所以想要一些建议。

由于恐慌和"柔软的";error是程序异常,应该保留non-nil error语义。您可以将错误包装在自定义类型或简单的错误变量中,并在函数调用后检查。

此外,为了实际修改返回的错误,您还应该:

  • 在延迟函数文字中使用recover()
  • 使用命名的返回参数

根据规范延期声明:

例如,如果延迟函数是一个函数文字,并且周围函数具有在文字范围内的命名结果参数,则延迟函数可以在返回之前访问和修改结果参数

package main
import (
"errors"
"fmt"
"log"
)
var ErrPanicRecovered = errors.New("recovered from panic")
// named return parameters
func recoverableFoo() (i int, err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("%w: %v", ErrPanicRecovered, r)
}
}()
// panic("problem!") // or any call that may panic; uncomment to test
return 1, nil
}

func main() {
x, err := foo()
if err != nil {
if errors.Is(err, ErrPanicRecovered) {
log.Fatal("panicked: ", err)
}
log.Printf("some other error: %s", err.Error())
return
}
fmt.Println("after foo x = " + fmt.Sprint(x))
}

特别是,将fmt.Errorf%w格式化谓词一起使用,可以正确地包装错误,然后使用errors.Is:进行检查

如果格式说明符包含带有错误操作数的%w谓词,则返回的错误将实现返回操作数的Unwrap方法。

游乐场:https://play.golang.org/p/p-JI1B0cw3x

最新更新