5. 高质量编程与编码规范
5.1. 编码规范
5.1.1. 代码格式
gofmt 是 Go 语言自带的一个工具,用于自动格式化 Go 代码,使其符合 Go 语言的官方代码风格。使用 gofmt 可以确保你的代码风格统一,提高可读性,同时避免不必要的格式问题。
- 格式化单个文件: 如果你想格式化一个单独的 Go 源代码文件,可以运行以下命令:
gofmt -w yourfile.go
-
-w选项会直接修改文件,将格式化后的代码写回到文件中。- 如果没有
-w选项,gofmt会将格式化后的代码输出到标准输出,但不会修改文件。
- 格式化整个目录: 如果你想格式化某个目录中的所有 Go 源文件,可以运行:
gofmt -w .
这会递归地格式化当前目录及其子目录中的所有 .go 文件。
- 仅检查格式化是否符合标准: 如果你只想检查文件是否已经符合 Go 格式,不进行修改,使用
-l选项:
gofmt -l .
这会列出所有未符合 Go 格式的文件,但不会修改它们。
- 与其他命令一起使用: 你还可以将
gofmt与其他命令结合使用。例如,你可以使用管道来直接格式化并输出文件内容,而不修改文件:
cat yourfile.go | gofmt
gofmt的格式化规则
gofmt 主要执行以下操作来统一代码格式:
- 缩进:使用 4 个空格进行缩进,不允许使用制表符(tab)。
- 行尾空格:删除所有行尾的空格。
- 大括号位置:Go 语言的开头大括号
{必须在函数定义和控制结构后面同一行(即没有独立的一行)。 - 空行:保留必要的空行(例如包声明、导入部分和函数定义之间的空行)。
- 空格:运算符两边通常会有空格,例如
a + b。 - 函数和变量声明:简洁的函数和变量声明格式(例如
var x = 10)。
5.1.2. 注释
- 注释的适用场景
- 注释应该解释代码作用:对一些公共符号
- 注释应该解释代码如何做的:相对来说复杂和不明显的逻辑进行说明
- 注释应该解释代码实现的原因:解释代码的外部因素、提供额外的上下文,解释为什么这么实现功能
- 注释应该解释代码什么情况会出错:解释代码的限制条件
- 公共符号始终要注释
- 包中声明的每个公共的符号(变量、常量、函数、结构)都需要添加注释
- 任何既不明显也不简短的公共功能必须予以注释
- 无论长度和复杂度如何,对库中的任何函数都必须注释
例外:接口方法的注释没有意义,直接不注释
注意
- 代码本身就是最好的注释
- 注释应该提供代码未表达出的上下文信息,而不是简单的重复介绍下代码的流程
5.1.3. 命名规范
变量名:简单大于冗长
index和i含义一样,仅限于for循环内部,没必要使用index。使用index没有对含义改变什么
变量名:有特定含义的时候要指定
- deadline是指截止时间,有特定的含义
- t常代指任何时间,因此不能将deadline换为t
变量名:驼峰规则缩略名全大写
函数名:包中的某函数名不用携带包的上下文
包名:只由小写字母组成,不包含大写字母和下划线
5.1.4. 控制流程
避免嵌套,保证正常流程清晰
可以省略else,因为return nil本来是在正常流程中的
尽量保证正常代码路径为最小缩进
也就是利用if判断的应该是异常情况
5.1.5. 错误和异常处理
简单错误
简单错误是指仅出现一次,且在其他地方不需要捕捉该错误
- 优先使用
errors.New来创建匿名变量来直接表示简单错误 - 如果有格式化的要求,则使用fmt.Errorf
错误的包装和解包
- 错误的包装(Wrap)提供了一个error嵌套另一个error的能力,从而生成error跟踪链
- 使用fmt.Errorf中使用%w关键字来将一个错误关联到错误链中
错误判定和错误获取
- 判断一个错误是否是特定错误,通过
errors.Is而不是==,这样可以检查整个错误链
- 在错误链上获取指定类型的错误,通过errors.AS