Go 语言中的错误和异常处理

在 Go 语言中没有与 Java 或者 .NET 类似的异常处理机制。Go 语言的开发者认为类似的异常处理已经被过多的使用了,这样的异常机制过度依赖上层代码对异常的处理,如果上层代码对异常的处理不到位会使程序出一些不易排查的BUG。所以为了让开发者能够重视并正确的处理每一个可能会出现异常的函数,Go语言采用返回值的形式来返回错误。这一机制,既可以让开发者真正理解错误处理的含义,也可以大大降低程序的复杂度。

1.error 接口

error 是系统自带的一个接口类型的自定义类型。

代码如下:

type error interface {
    Error() string
}

2. errors 包

Tips:包的概念会在后文的Go语言中的包管理中详细介绍

errors 包中包含了一个实现了 error 这个接口的结构体类型 errorString。我们可以直接使用包中的方法来自定义一些错误,从而返回我们希望被上层代码处理的错误信息。

代码示例:

package main

import (
    "errors"
    "fmt"
)

func main() {
    t, err := divide(2, 0)
    if err != nil {
        fmt.Println(err)
    } else {
        fmt.Println(t)
    }
}

func divide(a, b int) (int, error) {
    if b == 0 {
        return 0, errors.New("除数不能为0")
    }
    return a / b, nil
}
  • 第 19 行:使用 errors.New 自定义一个除数不能为0的错误;
  • 第 10~12 行:若除数为零,则输出这个错误。

执行结果:

image.png

3. 异常处理

如果你调用的方法的开发者不够仔细,并没有将所有的异常都考虑到并作为错误返回,那你的程序可能就会被其影响而崩溃。对这种情况,GO 语言提供了一个叫recover()的函数,用于处理这种问题。一般常用于服务启动的入口函数,因为网络等外部因素,极有可能会导致程序异常,这些异常就需要这个函数来捕获。

代码示例:

package main

import (
    "fmt"
)

func main() {
    defer func() {
        err := recover()
        if err != nil {
            fmt.Println("程序运行中出现异常:", err)
        }
    }()
    t := divide(2, 0)
    fmt.Println(t)
}

func divide(a, b int) int {
    return a / b
}
  • 第 17 行:在没有判断除数的情况下直接做除法,若除数为零,程序直接崩溃。
  • 第 8~11 行:在 main 函数结束时,获取执行过程中的错误,若没有错误者err为nil。

执行结果:

image.png

4. 小结

本位介绍了 Go 语言中如何使用 errors 来自定义错误,如何去使用函数中返回出来的 error 类型变量,来处理自定义错误以及在无法避免的异常出现的时候如何使用recover()来保障程序不崩溃。