【发布时间】:2020-07-19 17:47:12
【问题描述】:
我正在开发一个 CLI 工具,如果出现问题,我想记录自定义错误并恐慌退出。恐慌的问题是panic 的退出后面是我不想向用户显示的堆栈跟踪。有没有办法惊慌并有一个忍者般的隐秘/安静的出口?
(选择 panic 而不是 os.Exit() 因为这样可以处理任何 defer 并且看起来更干净。)
【问题讨论】:
标签: go
我正在开发一个 CLI 工具,如果出现问题,我想记录自定义错误并恐慌退出。恐慌的问题是panic 的退出后面是我不想向用户显示的堆栈跟踪。有没有办法惊慌并有一个忍者般的隐秘/安静的出口?
(选择 panic 而不是 os.Exit() 因为这样可以处理任何 defer 并且看起来更干净。)
【问题讨论】:
标签: go
嗯,直接回答是肯定的,有办法:
panic 带有自定义“哨兵”类型的错误,或带有自定义“哨兵”值的错误,然后main 中有一个defer-red 调用recover()-s 恐慌并检查返回值是否为哨兵类型(或等于哨兵值——具体方法取决于你) .panics。但老实说,我认为您的思维方式受到编程语言的影响太大了,但有例外:我还没有看到 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,因为,我必须承认,如果你已经这样做了,你可能一开始就不会问你的问题 ;-)
【讨论】: