5.2 测试多返回值函数的错误

    在第 4.7 节的程序 string_conversion.go 中,函数 strconv.Atoi 的作用是将一个字符串转换为一个整数。之前我们忽略了相关的错误检查:

    如果 origStr 不能被转换为整数,anInt 的值会变成 0 而 _ 无视了错误,程序会继续运行。

    这样做是非常不好的:程序应该在最接近的位置检查所有相关的错误,至少需要暗示用户有错误发生并对函数进行返回,甚至中断程序。

    我们在第二个版本中对代码进行了改进:

    示例 1:

    示例 5.3

    1. package main
    2. import (
    3. "fmt"
    4. "strconv"
    5. )
    6. func main() {
    7. var orig string = "ABC"
    8. // var an int
    9. var newS string
    10. // var err error
    11. fmt.Printf("The size of ints is: %d\n", strconv.IntSize)
    12. // anInt, err = strconv.Atoi(origStr)
    13. an, err := strconv.Atoi(orig)
    14. if err != nil {
    15. }
    16. fmt.Printf("The integer is %d\n", an)
    17. an = an + 5
    18. newS = strconv.Itoa(an)
    19. fmt.Printf("The new string is: %s\n", newS)
    20. }

    这是测试 err 变量是否包含一个真正的错误(if err != nil)的习惯用法。如果确实存在错误,则会打印相应的错误信息然后通过 return 提前结束函数的执行。我们还可以使用携带返回值的 return 形式,例如 return err。这样一来,函数的调用者就可以检查函数执行过程中是否存在错误了。

    习惯用法

    1. value, err := pack1.Function1(param1)
    2. if err != nil {
    3. fmt.Printf("An error occured in pack1.Function1 with parameter %v", param1)
    4. return err
    5. }
    6. // 未发生错误,继续执行:

    如果我们想要在错误发生的同时终止程序的运行,我们可以使用 os 包的 Exit 函数:

    习惯用法

    (此处的退出代码 1 可以使用外部脚本获取到)

    有时候,你会发现这种习惯用法被连续重复地使用在某段代码中。

    当没有错误发生时,代码继续运行就是唯一要做的事情,所以 if 语句块后面不需要使用 else 分支。

    示例 2:我们尝试通过 os.Open 方法打开一个名为 name 的只读文件:

    1. f, err := os.Open(name)
    2. if err != nil {
    3. return err
    4. doSomething(f) // 当没有错误发生时,文件对象被传入到某个函数中

    练习 5.1 尝试改写 string_conversion2.go 中的代码,要求使用 := 方法来对 err 进行赋值,哪些地方可以被修改?

    示例 3:可以将错误的获取放置在 if 语句的初始化部分:

    1. if err := file.Chmod(0664); err != nil {
    2. fmt.Println(err)
    3. return err
    4. }

    示例 4:或者将 ok-pattern 的获取放置在 if 语句的初始化部分,然后进行判断:

    习惯用法

    注意事项

    如果您像下面一样,没有为多返回值的函数准备足够的变量来存放结果:

    1. func mySqrt(f float64) (v float64, ok bool) {
    2. if f < 0 { return } // error case
    3. return math.Sqrt(f),true
    4. }
    5. func main() {
    6. t := mySqrt(25.0)
    7. fmt.Println(t)
    8. }

    您会得到一个编译错误:multiple-value mySqrt() in single-value context

    正确的做法是:

    1. t, ok := mySqrt(25.0)
    2. if ok { fmt.Println(t) }

    注意事项 2

    当您将字符串转换为整数时,且确定转换一定能够成功时,可以将 Atoi 函数进行一层忽略错误的封装:

    当打印到控制台时,可以将该函数返回的错误忽略;但当输出到文件流、网络流等具有不确定因素的输出对象时,应该始终检查是否有错误发生(另见练习 6.1b)。