常用的有五种方式

第一种策略

首先,也是最常用的方式是传播错误。这意味着函数中某个子程序的失败,会变成该函数的失败。我们使用该函数前缀添加额外的上下文信息到原始错误信息。当错误最终由main函数处理时,错误信息应提供清晰的从原因到后果的因果链,就像美国宇航局事故调查时做的那样:

genesis: crashed: no parachute: G-switch failed: bad relay orientation

编写错误信息时,我们要确保错误信息对问题细节的描述是详尽的。尤其是要注意错误信息表达的一致性,即相同的函数或同包内的同一组函数返回的错误在构成和处理方式上是相似的。


第二种策略

第二种策略。如果错误的发生是偶然性的,或由不可预知的问题导致的。一个明智的选择是重新尝试失败的操作。在重试时,我们需要限制重试的时间间隔或重试的次数,防止无限制的重试。

第三种策略

如果错误发生后,程序无法继续运行,我们就可以采用第三种策略:输出错误信息并结束程序。需要注意的是,这种策略只应在main中执行。对库函数而言,应仅向上传播错误,除非该错误意味着程序内部包含不一致性,即遇到了bug,才能在库函数中结束程序。

调用log.Fatalf可以更简洁的代码达到与上文相同的效果。log中的所有函数,都默认会在错误信息之前输出时间信息。

if err := WaitForServer(url); err != nil {
    log.Fatalf("Site is down: %v\n", err)
}
// 我们可以设置log的前缀信息屏蔽时间信息,一般而言,前缀信息会被设置成命令名。

log.SetPrefix("wait: ")
log.SetFlags(0)

第四种策略

第四种策略:有时,我们只需要输出错误信息就足够了,不需要中断程序的运行。

我们可以通过log包提供函数

if err := Ping(); err != nil {
    log.Printf("ping failed: %v; networking disabled",err)
}
//log包中的所有函数会为没有换行符的字符串增加换行符。

或者标准错误流输出错误信息。

if err := Ping(); err != nil {
    fmt.Fprintf(os.Stderr, "ping failed: %v; networking disabled\n", err)
}

第五种策略

第五种,也是最后一种策略:我们可以直接忽略掉错误。

文件结尾错误(EOF)

io包保证任何由文件结束引起的读取失败都返回同一个错误——io.EOF