Go语言-高质量编程2 | 青训营笔记

74 阅读2分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第6天。

4.控制流程

  • 避免嵌套,保持正常流程清晰,例如:如果两个分支中都包含return语句,则可以去除冗余的else
  • 尽量保持正常代码路径为最小缩减,优先处理错误情况/特殊情况,尽早返回或继续循环来减少嵌套

5.错误和异常处理

简单错误

  • 简单错误指仅出现一次的错误,且在其他地方不需要捕获该错误
  • 优先使用errors.News来创建匿名变量来直接表示简单错误
  • 如有格式化需求,使用fmt.Errorf
func defaultCheckRedirect(req *Request, via []*Request) error {
    if len(via) >= 10{
        return errors.New("stopped after 10 redirects")
    }
    return nil
}

错误的Wrap和Unwrap

  • 错误的 Wrap 提供一个error嵌套另一个error的能力,形成error的跟踪链
  • 在fmt.Errorf中使用:%w关键字将一个错误关联至错误链中
return fmt.Errorf("return srcfiles list: %w", err)

错误判定

// 判断一个错误是否为特定错误
// 不同于使用==,该方法判定错误链上所有错误是否包含特定的错误
error.Is(err, fs.ErrNotExist)

//在错误链上获取特定种类的错误
errors.As(err, &pathError)

panic

recover

在当前goroutine的被defer的函数中生效。

defer语句会在函数返回前调用。

多个defer语句运行顺序是后进先出。

二、性能优化建议

1.Benchmark

go test -bench=. -benchmen

2.Slice

尽可能在使用make()初始化内存时提供容量信息。

3.Map

  • 不断向map添加元素会触发扩容
  • 提前分配好空间可以减少内存拷贝和Rehash的消耗
  • 建议根据实际需求提前预估需要的空间

4.字符串处理

使用 + 拼接性能最差,strings.Builder,bytes.Buffer 相近,strings.Buffer 更快。

分析:

  • 字符串在Go语言中是不可变类型,占用内存大小固定
  • 使用 + 每次会重新分配内存
  • strings.Builder,bytes.Buffer 底层都是 []byte 数组
  • 内存扩容策略,不需要每次拼接重新分配内存
  • bytes.Buffer转化为字符串时重新申请一块空间
  • strings.Builder直接将底层的[]byte转换成字符串类型返回

5.空结构体

  • 空结构体struct{}实例不占据内存空间
  • 可作为各种场景下的占位符使用
// 实现Set,可以考虑用map代替
// 对于这个场景,只需用map的键,不需要值
func EmptyStructMap(n int) {
    m := make(map[int]struct{})
    for i := 0; i < n; i++ {
        m[i] = struct{}{}
    }
}

6.atomic包