当前位置: 首页 > 知识库问答 >
问题:

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

安泰平
2023-03-14

我有以下代码:

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")
    }
}

在错误处理和从恐慌中恢复方面,他们的东西是我遗漏的。我是新来的,所以想要一些建议。

共有1个答案

吴山
2023-03-14

由于panic和“soft”错误都是程序异常,所以应该保留非零错误语义。您可以将错误包装在自定义类型或简单的错误变量中,并在函数调用后检查。

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

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

从Defer语句的规格来看:

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

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谓词,则返回的错误将实现返回操作数的解缠方法。

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

 类似资料:
  • 代码块: 这是否可以在围棋中实现,就像当恐慌发生时,我们可以以某种方式恢复并完成我们的循环?

  • 问题内容: 在defer函数中,我想查看一次恢复调用是否会产生非nil值(不恢复) 可能吗? 问题答案: 那确切的事情是不可能的。您可能只想重新恐慌,就像在其他语言中重新引发异常一样。

  • 作为一个新的围棋爱好者,试图使用围棋的错误处理方式。明确地说--我喜欢例外。 我有一个服务器,它接受一个连接,处理一组请求并答复它们。我发现我可以做 在深层处理代码中 null 我觉得答案是“是的,它可以工作”,可以在您自己的代码中使用,但panic不应该被用于更广泛用途的库使用。库的标准和礼貌的行为方式是通过错误返回

  • 我试图从我的程序中创建的go例程中捕捉崩溃/恐慌,以便将它们发送到我的崩溃错误报告服务器(如Sentry/Raygun) 例如, 做这件事的惯用方法是什么?