这是我参与「第五届青训营 」伴学笔记创作活动的第 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([]int,2) copy( result, origin[len(origin)-2: ]) return result }
- 预分配内存
- map
- 预分配内存
data := make(map[int]int, size)
- 预分配内存
- 字符串
- 使用strings.Builder
- 底层是byte数组,但是对字符串优化过,比bytes.Buffer更好(bytes.Buffer转化字符串时重新申请了一块空间,而strings.Builder直接转换)
- 使用strings.Builder
- 使用空结构体节省内存
- 不占内存空间
- 用在Map上实现Set
- 尝试使用atomic包
- 其通过硬件实现,效率更高
- 保护变量
- sync.Mutex 用于保护一段逻辑,保护变量太奢侈
- 非数值操作,可以使用atomic.Value,能承载一个interface{}
- 其通过硬件实现,效率更高