高质量编程
高质量代码:正确可靠,简洁清晰
代码格式:使用gofmt格式化代码,goimports在此基础上加入了依赖包管理功能
注释:解释代码作用、为何实现、具体实现过程、什么情况会出错(限制条件)。解释公共符号:变量、常量、函数、结构体、公共功能、所有库函数
命名规范:
- 变量:缩略词全大写,但当其位于变量开头且不需要导出时,使用全小写,如ServerHTTP,xmlHTTPRequest;变量距离其被使用的地方越远,需要携带越多的上下文信息
- 函数:驼峰命名法,首字母大写。如果属于一个包,就不用带这个包的名字。比如http.Serve()而不是http.ServeHTTP()
- package:只有小写字母,不能与标准库、变量名同名,包含一定上下文信息,使用单数
控制流程:
- 避免嵌套,优先处理特殊情况,尽早返回或者继续循环
- 从上到下是正常流程代码
错误和异常处理
- 简单错误:仅出现一次的,使用errors.New来创建匿名变量表示简单错误,或者使用fmt.Errorf格式化
- error通过Wrap(%w)进行嵌套,生成跟踪链
- 使用
errors.Is()判断一个错误是否为特定的某个错误,整个错误链都会比较;errors.As()在错误链上获取特定错误 - panic(string):触发异常,一般业务中不使用
- recover:从panic的异常状态中恢复,在当前goroutine的被defer的函数中使用
性能优化
- Benchmark工具:
go test -bench=. -benchmem运行所有基准测试,并显示每个测试的内存分配信息 - 生成slice时预分配内存:
data := make([]int,0,size) - 在从一个切片中取某几个元素时,使用copy()替代直接取元素,因为直接取元素的话即使原来的切片不用也不会被释放,copy出来以后原来的切片就可以释放了
- map预分配内存:
data := make(map[int]int, size) - 字符串拼接:使用strings.Builder代替+=,因为+每次都需要重新分配内存,strings.Builder底层是[]byte数组
- 空结构体:不占用空间,将map作为Set使用时可作为占位符,
s[key]=struct{}{},因为只需要key - atomic包:原子操作,通过硬件实现,相比系统调用实现的锁操作,atomic效率更高