编码技巧
编码技巧
错误处理
错误是值,实现 Error() string 接口
不仅仅是检查错误,还要优雅处理
堆栈信息对错误不友好,难以阅读和解析,只能告诉我们哪里出错了,却不能告诉我们为什么会出错(问题的根源)
使用 Wrap 进行包装后,使得错误更容易被定位
func doSometing() ([]int, error) {
i1, err := pkg.GetOne()
if err != nil {
return nil, errors.Wrap(err, "Err when get one")
}
i2, err := pkg.GetTwo()
if err != nil {
return nil, errors.Wrap(err, "Err when get two")
}
i3, err := pkg.GetThree()
if err != nil {
return nil, errors.Wrap(err, "Err when get three")
}
return []int{i1, i2, i3}, nil
}更好的错误定义:
- 根据严重程度分类,logrus.Level 对错误进行分级
- 根据类型分类,可以仅返回错误类型给客户端,更详细的自定义错误可以包含(操作类似栈信息,错误类型,其他信息)
- 加上应用程序特有的数据
- 易检索
强烈建议在需要长期维护的系统中加入自定义的错误包,区分系统错误以及用户级错误
没有错误的返回值最好直接写 nil ,否则可能会返回永远为非 nil 的错误!!
chan
closed chan: 已关闭的 channel 可以用来进行协程同步
package main
import "sync"
func main() {
var ch = make(chan struct{})
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func(n int) {
<-ch // 等待close(ch),所有协程同时开始
println(n)
wg.Done()
}(i)
}
close(ch)
wg.Wait()
}原则:
- 无论怎样都不应该在接收端关闭通道
- 同一个通道仅允许关闭一次
- clsoe 一个 nil 的通道会 panic
- 参数应该声明成单向通道对使用者进行约束
只发送:c chan<- T 只接收:c <-chan T
不能 for range 一个未初始化的通道
设计原则
面向接口编程:抽象出核心动作变成接口,解耦具体结构和形式,具体的结构体应为包级私有,提供初始化函数返回接口类型的对象