高质量Go编码 | 青训营笔记

38 阅读2分钟

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

规范

  • 代码格式
    • gofmt 官方工具
  • 注释
    • 代码作用
    • 代码如何做
    • 代码实现的原因
      • 上下文
    • 什么时候出错
  • 命名规范
    • 变量
      • 简洁
      • 缩略词全大写,处于开头且不需要导出可以全小写
    • 函数
      • 不携带包名的上下文信息
      • 函数名尽量简短
      • 小写字母,不包含大写字母和下划线
      • 不与标准库同名
      • 不使用常用变量名作为包名
      • 使用单数而不是复数
      • 谨慎的使用缩写
  • 控制流程
    • 避免嵌套
    • 保持正常代码最小缩进
      • 优先处理错误,尽早返回
  • 错误和异常处理
    • 简单错误
      • 只出现一次,其他地方不需要捕获
      • errors.New
      • fmt.Errorf
    • 错误的Wrap和Unwrap
      • fmt . Errorf( " reading srcfiles list: %w" , err)
      • 错误链
    • 错误判定
      • errors.Is
        • 可以判定错误链上的所有错误是否含有特定错误
      • errors.As
        • 错误链上获取特定种类的错误
    • panic
      • 业务代码不使用
      • 用于启动初始化阶段
    • recover
      • 恢复panic
      • 只在当前协程有效

单元和基准测试方法

以下面代码为例

// main.go
package main

import "fmt"

func main() {
   fmt.Println(Add(1, 2))
}
func Add(i, j int) int {
   return i + j
}

想要测试Add函数

package main

import (
   "testing"
)

func TestAdd(t *testing.T) {
   if Add(1, 2) != 3 {
      t.Error("Add(1, 2) == ", Add(1, 2))
   }
}

func BenchmarkAdd(b *testing.B) {
   // 初始化代码
   b.ResetTimer()
   for i := 0; i < b.N; i++ {
      Add(1, 2)
   }
   // 回收资源
}

测试命令

# go test 运行所有单元测试
go test -v -run="Add"
# go test -bench=. 匹配所有的基准测试
go test -bench=Add
# 针对内存分析
go test -bench=Add -benchmem

性能优化建议

  • slice
    • 预分配内存
      • data := make([]int,0, size) // 类型,长度,容量
    • 大内存未释放陷阱
      • 大的切片创建小切片
      • 使用copy代替
      func GetLastByCopy(origin []int) []int {
          result := make([]int2)
          copy( result, origin[len(origin)-2: ])
          return result
      }
      
  • map
    • 预分配内存
      • data := make(map[int]int, size)
  • 字符串
    • 使用strings.Builder
      • 底层是byte数组,但是对字符串优化过,比bytes.Buffer更好(bytes.Buffer转化字符串时重新申请了一块空间,而strings.Builder直接转换)
  • 使用空结构体节省内存
    • 不占内存空间
    • 用在Map上实现Set
  • 尝试使用atomic包
    • 其通过硬件实现,效率更高
      • 保护变量
    • sync.Mutex 用于保护一段逻辑,保护变量太奢侈
    • 非数值操作,可以使用atomic.Value,能承载一个interface{}