编码技巧

编码技巧

错误处理

错误是值,实现 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 一个未初始化的通道

设计原则

面向接口编程:抽象出核心动作变成接口,解耦具体结构和形式,具体的结构体应为包级私有,提供初始化函数返回接口类型的对象