这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天
内容源于青训营课堂视频以及一些go文档和自己的经验、理解,若有错误欢迎及时指出
1 简介
什么是高质量——编写的代码能达到正确可靠、简洁清晰的目标可称之为高质量代码
- 边界条件是否考虑完备
- 异常处理,保证稳定性
- 易读易维护
编程原则
Dave Cheney
- 简单性
- 消除“多余的复杂性”,以简单清晰的逻辑编写代码
- 难以理解的代码逻辑,排查问题时难以定位,不知道如何修复
- 可读性
- 代码是写给人看的,而不是机器
- 编写可维护代码的第一步是确保代码可读
- 生产力
- 团队整体的工作效率非常重要
2 编码规范
-
代码格式
gofmt/goimports都是官方提供的工具
-
注释
- 解释代码作用:公共符号...
- 解释代码如何做的:实现过程...
- 解释代码实现的原因:解释代码的外部因素,提供额外的上下文信息...
- 解释代码什么时候会出错:限制条件...
公共符号始终要注释说明
-
命名规范
- 简洁胜于冗长
- 1.1缩略词全大写,但位于变量开头且不需要导出时全小写
ServerHTTP而不是ServerHttpXMLHTTPRequest或者xmlHTTPRequest
- 1.2变量距离被使用的地方越远,则需要携带越多的信息
- 2.1函数名不用携带包名的上下文信息,因为常常同时出现
http.Server而不是http.ServerHTTP
- 3.1包名只由小写字母组成,不含大写字母和下划线等字符
- 3.2简短并包含一定的上下文信息
- 3.3不与标准库同名
-
控制流程
-
避免嵌套,保持清晰
-
尽量保持正常代码路径为最小缩进
-
优先处理错误/特殊情况,尽早返回或继续循环来减少嵌套
将两层循环改写为线性的:
if err := doSomething(); err != nil { return err } if err := doAnotherThing(); err != nil { return err }
-
-
线性原则,处理逻辑尽量走直线,避免复杂的分支嵌套
-
-
错误和异常处理
-
简单错误
- 指仅出现一次,且在其他地方不需要捕获
- 优先使用
errors.New()创建匿名变量直接表示 - 格式化可使用
fmt.Errorf
-
错误的包装和解包装
-
实际上是提供了error嵌套的能力,生成一个error跟踪链
-
fmt.Errorf中使用%w来将一个错误关联至一个错误链if err := doSomething(); err != nil { return fmt.Errorf("test error warp: %w", err) }
-
-
错误判定
- 判定一个错误是否是特点错误,使用
error.Is- 不同于使用
==,使用该方法可以判定判定错误链上所有错误是否含有特定错误
- 不同于使用
- 获取错误链上的特定种类错误,使用
error.As- 与is的区别在于as会提取出调用链中指定类型的错误,并将错误赋值给变量,便于后续处理
- panic
- 业务代码中不建议使用
- 调用函数不含recover会造成程序崩溃
- 使用error代替panic
- 当程序启动阶段发生不可逆转的错误时,可在init或main中使用panic
- recover
- 只能在被defer的函数中使用
- 嵌套不生效
- 只在当前gorouine中生效
- defer语句是后进先出:形成了栈,后面的语句会依赖前面的资源,因此如果先前面的资源先释放了,后面的语句就没法执行了
- 判定一个错误是否是特点错误,使用
-
3 性能优化建议
简介
- 性能优化的前提是满足正确可靠、简洁清晰等质量因素
- 性能优化是综合评估,时空效率可能对立
方式
-
Benchmark
- 基准测试
-
slice
- 预分配内存
- 使用copy代替re-slice
-
map
- 预分配内存
-
字符串处理
- 使用
strings.Builder - 使用+性能最差
- 使用
-
空结构体
-
atomic包
- 系统调用,硬件实现