错误处理是Go语言一个非常重要的特性,这是因为,几乎所有的Go函数都返回一个错误信息或者nil,这是Go语言表达函数执行是否遇到错误的方式。你很可能对下面这样的代码感到厌倦,不管是在本书还是在其他你可以找到每一个Go程序中:
if err != nil {
fmt.Println(err)
os.Exit(10)
}
上面的代码在屏幕上打印错误信息,并用os.Exit()
退出。请注意,你可以通过在main()
函数中调用关键词return
来退出程序。一般而言,在非main()
函数中,调用os.Exit()是
不推荐的。非main()
函数倾向返回错误信息,退出应该被函数调用者处理。
如果你希望把错误信息发送到日志而不是打印到屏幕,你可以使用下面这个段代码:
if err != nil {
log.Println(err)
os.Exit(10)
}
最后,上面的代码还有一种变化,当程序发生严重错误而你想终止程序,你可以这样:
if err != nil {
panic(err)
os.Exit(10)
}
Panic是一个内置Go函数,用来停止程序运行,开始panicking
。如果你发现自己使用panic
太频繁,你可能需要重新考虑你的代码实现。我们应该尽量避免使用panic
,多用errors
。
你会在下一章中看到,Go还提供了一个函数recover()
,这个函数或许可以把你从困难的处境中拯救出来。目前,你需要等到第二章,理解go内部实现,来学习panic
和recover
这一对组合的威力。
现在我们来看一个Go程序,不仅处理函数产生的错误信息,还定义自己的错误信息。这个程序的名字是errors.go
,分五部分展示。你会看到这个程序改进了之间看到的cla.go
程序,检查了命令行参数是否是可接受的浮点数。
第一部分是这样的:
package main
import (
"errors"
"fmt"
"os"
"strconv"
)
这部分代码导入了我们需要的包。
然后看第二部分:
func main() {
if len(os.Args) == 1 {
fmt.Println("Please give one or more floats.")
os.Exit(1)
}
arguments := os.Args
var err error = errors.New("An error")
k := 1
var n float64
这里,你创建了一个新的error
变量,命名为err,并且用自定义的值初始化了这个变量。
第三部分:
for err != nil {
if k >= len(arguments) {
fmt.Println("None of the arguments is a float!")
return
}
n, err = strconv.ParseFloat(arguments[k], 64)
k++
}
min, max := n, n
这是程序最困难的部分。如果第一个命令行参数不是合适的浮点型,你需要继续检查下一个,直到找到一个合适的参数。如果所有的参数格式都不对,程序会终止,然后打印信息到屏幕。所有的这些检查都是通过查看函数strconv.ParseFloat()
返回的error的值。所有的这些代码都是为了正确的初始化变量max
和min
。
来看第四部分:
for i := 2; i < len(arguments); i++ {
n, err := strconv.ParseFloat(arguments[i], 64)
if err == nil {
if n < min {
min = n
}
if n > max {
max = n
}
}
}
这样,为了找出参数中的最大值和最小值,处理了所有正确的命令行参数。
最后,程序的最后部分就是打印变量max
和min
的当前的值:
fmt.Println("Min:", min)
fmt.Println("Max:", max)
}
从程序errors.go
可以看出,大部分的代码都是错误处理,而不是程序实际上的功能逻辑。不幸的是,这就是大部分用Go开发现代软件的现状,其他语言也是。
如果执行这个程序,你会得到以下输出:
$ go run errors.go a b c
None of the arguments is a float!
$ go run errors.go b c 1 2 3 c -1 100 -200 a Min: -200
Max: 100