在开始编写 Golang 代码之前, 先随便引入了一个 MYSQL 的包, 准备简单写写对数据库的操作.
但是刚一上手就发现一个问题, 如何处理引入包抛出的各种异常问题呢?
如何抛出一个错误
首先了解一下 error 类型:
1 | type error interface { |
创建 error 实例:
1 | errors.New('Error Message') |
自定义 error 类型, 相当于实现了 error 接口:
1 | type ParamError struct { |
如何处理错误
一般情况分为三种:
函数返回的错误: 使用特定值来判定函数执行状态.
1
2
3
4
5
6buf := make([]byte, 100)
n, err := r.Read(buf)
buf = buf[:n]
if err == io.EOF {
log.Fatal("read failed", err)
}不建议使用, 因为这样判断可能增加包依赖, 项目大了会很难维护, 或者出现循环引用.
特定错误: 使用自定义类型, 上层使用断言.
1
2
3
4
5
6
7
8switch err := (interface{})(err).(type) {
case nil:
fmt.Println(val)
case *MyError:
fmt.Println("Error Happens ", err.Error())
default:
// unknown
}1
2
3
4
5errMsg, ok := (interface{})(err).(*MyError)
fmt.Printf("ok %v errMsg %s\n", ok, errMsg) // errMsg 由 Error() 方法返回.
if ok {
fmt.Println("Error is MyError type")
}不建议使用, 每次都要使用别人的类来做判断, 耦合性高, 使接口脆弱.
不透明的错误处理: 获取到 nil 向下执行, 非 nil 当成未知错误无法处理直接向上抛出.
1
2
3
4
5
6
7func foo() error {
val, err := bar.Foobar()
if err != nil {
return err
}
// use val
}这种是最好的方法.
一些特殊的情况
自定义一些更详尽有针对性的错误
有时直接 return err
会造成在顶部准备处理错误的时候, 发现错误并非能准确定位.
这时需要手动生成一些更有针对性的错误 return fmt.Errorf('auth failed: %v', err)
.
参考 github.com/pkg/errors
包, 打印出错误同时, 输出堆栈信息.
给错误自定义行为
给错误定义一些方法, 用这些方法实现错误的一些判断.
遇到错误不忽略, 不重复处理
参考文档
- 博客: https://ethancai.github.io/2017/12/29/Error-Handling-in-Go/
- 错误处理示例: https://github.com/EthanCai/goErrorHandlingSample
- The Go Blog
- Dave Cheney
- Go Packages
- pkg: Artisanal, hand crafted, barrel aged, Go packages