运行在生产环境中的代码必须避免panics。Panics 是 cascading failures 级联失败的主要根源。如果有错误发生,函数必须返回一个错误并且允许调用者决定如何处理它。
Bad
func run(args []string) {
if len(args) == 0 {
//直接panic了
panic("an argument is required")
}
// ...
}
func main() {
run(os.Args[1:])
}
Good
func run(args []string) error {
if len(args) == 0 {
//新建一个error
return errors.New("an argument is required")
}
// ...
return nil
}
func main() {
//调用方判断是否有错误发生
if err := run(os.Args[1:]); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
Panic/recover 并不是一个错误处理策略。只有当不可恢复的事情发生时,例如nil引用,程序才必须panic。
这样做的一个例外是程序初始化:在程序启动时发生的应该中止程序的坏的事情,可能会引起恐慌。
var _statusTemplate = template.Must(template.New("name").Parse("_statusHTML"))
即使在测试代码中,也应该优先使用t.Fatal
或者t.FailNow,
而不是 panic 来确保测试结果被标记为失败。
Bad
// func TestFoo(t *testing.T)
f, err := ioutil.TempFile("", "test")
if err != nil {
panic("failed to set up test")
}
Good
// func TestFoo(t *testing.T)
f, err := ioutil.TempFile("", "test")
if err != nil {
t.Fatal("failed to set up test")
}