Error handling Go中更简洁的错误处理

Error handling Go中更简洁的错误处理,error-handling,exception-handling,go,Error Handling,Exception Handling,Go,如何处理围棋中的大量错误 我查看了我的代码,发现其中充满了错误处理程序: err = result.Scan(&bot.BID, &bot.LANGUAGE, &bot.SOURCE) if err != nil { log.Fatalf("result.Scan: %v", err) return } fileName, err := copySourceToTemporaryFile(bot) if err != nil { log.Fata

如何处理围棋中的大量错误

我查看了我的代码,发现其中充满了错误处理程序:

err = result.Scan(&bot.BID, &bot.LANGUAGE, &bot.SOURCE)
if err != nil {
    log.Fatalf("result.Scan: %v", err)
    return
}

fileName, err := copySourceToTemporaryFile(bot)
if err != nil {
    log.Fatalf("copySourceToTemporaryFile: %v", err)
    return
}
...
许多线条看起来像:

// do something
// handle error
// handle error
// handle error

// do something 2
// handle error
// handle error
// handle error

我可以创建一个默认的处理程序来打印错误并停止处理,或者至少将这个“错误处理程序垃圾”从我的代码逻辑中移出吗?

这让我想起了Rob Pike最近的一个错误处理程序,以及

然而,关键的教训是错误是值,Go编程语言的全部功能可用于处理它们

值得强调的是,无论设计如何,程序都必须检查错误,无论它们是如何暴露的。这里的讨论不是关于如何避免检查错误,而是关于使用语言优雅地处理错误

一种技术是定义一个名为
errWriter
的对象:

type errWriter struct {
    w   io.Writer
    err error
}
write
方法调用底层
Writer
的write方法,并记录第一个错误以供将来参考:

一旦发生错误,
write
方法将变为no op,但
error
值将被保存

给定
errWriter
类型及其写入方法,可以重构上述代码:


如果
错误
是“真实的”,如果不希望在运行时出现意外的恐慌,您应该(必须)处理它

为了补充VonC关于
errWriter
技术的回答,您可以在更多情况下减少错误处理代码:

在这些情况下,您知道即使函数或方法可能返回
错误
,它也不会返回(例如,您从源代码中提供参数,您知道这些参数可以工作)。在这些情况下,您(或库的作者)可以提供帮助函数(或方法),这些函数不会返回
错误
,但如果错误仍然发生,会引发运行时死机

和包就是很好的例子:如果您在编译时提供了有效的模板或regexp,那么您可以确保在运行时对它们进行解析时不会出错。因此,
模板
包提供函数,
regexp
包提供函数:它们不会返回
错误
s,因为它们的预期用途是保证输入有效的地方

示例:

// "text" is a valid template, parsing it will not fail
var t = template.Must(template.New("name").Parse("text"))

// `^[a-z]+\[[0-9]+\]$` is a valid regexp, always compiles
var validID = regexp.MustCompile(`^[a-z]+\[[0-9]+\]$`)

我以前读过。如果我调用的方法不仅返回错误,而且还返回不同类型的结构,那会怎么样?一开始看起来很难看(后来也一样),但我恰好喜欢这种错误捕获。这真的让我想到:“在这种情况下,我应该怎么做?我应该崩溃(致命),我应该继续使用其他方法/默认值,还是应该询问用户”。如果您执行
log.Fatalf()
操作,您可以定义一个方法
CrashIfErr(errerror)
,只需调用
log.Fatalf()
。顺便说一句:在
log.Fatalf()
之后不需要
return
。我喜欢
Mustxxx
方法,它可以简化错误管理并澄清期望+1.
ew := &errWriter{w: fd}
ew.write(p0[a:b])
ew.write(p1[c:d])
ew.write(p2[e:f])
// and so on
if ew.err != nil {
    return ew.err
}
// "text" is a valid template, parsing it will not fail
var t = template.Must(template.New("name").Parse("text"))

// `^[a-z]+\[[0-9]+\]$` is a valid regexp, always compiles
var validID = regexp.MustCompile(`^[a-z]+\[[0-9]+\]$`)