Go语言学习06-错误处理
Go的错误机制
与其他主要编程语言的差异
-
没有异常机制
-
error
类型实现了error接口 -
可以通过 errors.New 来快速创建错误实例
gotype error interface { Error() string } errors.New("n must be in range [0, 10]")
最佳实践
定义不同的错误变量, 以便于判断错误类型
go
var LessThanTwoError = errors.New("n should be not less than 2")
var LargeThanHundredError = errors.New("n should be not larger than 100")
func GetFibonacci(n int) ([]int, error) {
if n < 2 {
return nil, LessThanTwoError
}
if n > 100 {
return nil, LargeThanHundredError
}
fibList := []int{1, 1}
for i := 2; i < n; i++ {
fibList = append(fibList, fibList[i-2]+fibList[i-1])
}
return fibList, nil
}
func TestGetFibonacci(t *testing.T) {
if v, err := GetFibonacci(-10); err != nil {
if err == LessThanTwoError {
fmt.Println("It is less.")
}
t.Error(err)
} else {
t.Log(v)
}
}
及早失败, 避免嵌套!
panic
- panic 用于不可恢复的错误
- panic 退出前会执行 defer 指定的内容
panic vs. os.Exit
- os.Exit 退出时不会调用 defer 指定的函数
- os.Exit 退出时不输出当前调用栈信息
recover
go
// 最常见的"错误恢复"
defer func() {
if err := recover(); err != nil {
Log.Error("recovered panic", err)
}
}()
缺陷:
- 形成僵尸服务进程, 导致 health check 失效
- "Let it Crash!" 往往是我们恢复不确定性错误的最好方法
Go语言学习07-包和依赖管理
package
-
基本复用模块单元
以首字母大写来表明可被包外代码访问
-
代码的 package 可以和所在的目录不一致
-
同一目录里的 Go 代码的 package 要保持一致
-
通过
go get
来获取远程依赖go get -u
强制从网络更新远程依赖 -
注意代码在 GitHub 上的组织形式, 以适应
go get
直接以代码路径开始, 不要有 src
init 方法
- 在 main 被执行前, 所有依赖的 package 的 init 方法都会被执行
- 不同包的 init 函数按照包导入的依赖关系决定执行顺序
- 每个包可以有多个init函数
- 包的每个源文件也可以有多个init函数, 这点比较特殊
Go 未解决的依赖问题
- 统一环境下, 不同项目使用同一包的不同版本
- 无法管理对包的特定版本的依赖
vendor 路径
随着Go 1.5 release 版本的发布, vendor目录被添加到除了GOPATH 和GOROOT之外的依赖目录查找的解决方案。在Go 1.6之前,你需要手动的设置环境变量
查找依赖包路径的解决方案如下:
- 当前包下的 vendor 目录
- 向上级目录查找, 知道找到 src 下的 vendor 目录
- 在 GOPATH 下面查找依赖包
- 在 GOROOT 目录下查找
常用的依赖管理工具
godep https://github.com/tools/godep