我正在开发一个 CLI 工具,如果出现问题,我想记录自定义错误并 panic 退出。 panic 的问题是panic
的退出后面是我不想向用户显示的堆栈跟踪。有没有办法 panic 并有一个忍者般的隐秘/安静的导出?
(选择 panic
而不是 os.Exit() 因为它可以处理任何 defer
并且看起来更干净。)
最佳答案
嗯,直接回答是肯定的,有办法:
panic
带有自定义错误“哨兵”类型或自定义“哨兵”值,然后 defer
-红色调用 main
其中recover()
-s panic 并检查返回的值是否为哨兵类型(或等于哨兵值 - 确切的方法取决于您)。如果它检测到“已知”错误,它会以非零退出代码静默退出;
否则
panic
再次。 但老实说,我认为您的思维方式受到编程语言的影响太大了,但有异常(exception):我还没有看到 CLI 应用程序在“以通常方式”处理错误时会遇到任何困难,或者实际上会从使用
panic
的救助中受益。 .与您渴望的方法相反的论点是:冒泡错误允许在展开的调用堆栈的每个级别上为其添加更多上下文,这是有意义的——产生尽可能有用的错误以显示。
基本上,它是这样工作的:
func main() {
...
err := DoStuff()
if err != nil {
log.Fatal("failed to do stuff: ", err)
}
...
}
func DoStuff() error {
foo, err := InitializeWhatever()
if err != nil {
return fmt.Errorf("failed to inialize whatever: %w", err)
}
...
return nil
}
func InitializeWhatever() (*Whatever, error) {
handle, err := OpenWhateverElse()
if err != nil {
return nil, fmt.Errorf("failed to open whatever else: %w", err)
}
...
return whatever, nil
}
…这会产生类似的东西failed to do stuff: failed to inialize whatever: failed to open whatever else: task failed successfully
......这清楚地表明哪些事件序列导致了不希望的结果。当然,像往常一样,YMMV,除了你之外没有人最了解你的情况,但这仍然是值得思考的事情。
这是我上面所写内容的各种想法列表。
net/http.ErrAbortHandler
.encoding/json
包用于使用这种方法来打破多个嵌套循环(尽管从那时起已经重新设计)。 net.Error
有 Timeout
和 Temporary
允许没有针对临时错误和由于超时导致的错误及其组合的具体导出类型的方法,而是让它们都支持一组通用的方法,这些方法允许调用者理解错误的性质。 好吧,我建议阅读 this因为,我必须承认,如果你已经这样做了,你可能一开始就不会问你的问题;-)
关于go - 如何在 Go 中的 `panic` 之后抑制堆栈跟踪?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62983700/