Go 编码规范
Gofmt
使用工具统一代码风格,目前默认使用 goimports
。vscode 中配置即可
Comment Sentences
注释文档应该是完整的句子, 并且要以名字作为开始,注释结束。
// Request represents a request to run a command.
type Request struct{
...
}
Contexts
Context
可以携带安全凭证,追踪信息,超时和关闭信号用来处理 API
和处理边界。 context
在函数签名作为第一个参数显示传递,参数名称为 ctx
。
Context
不要嵌入到结构体中,而是使用结构体方法进行使用。不要创建自定义 Context
类型。
Context
是不会改变的。
Copying
在进行拷贝时,要注意拷贝后的值进行操作时不会影响原值。
通常,不要拷贝含有指针方法类型的值。
Crypto Rand
使用 crypto/rand
进行随机加密,而不要使用 math/rand
。
import (
"crypto/rand"
// "encoding/base64"
// "encoding/hex"
"fmt"
)
func Key() string {
buf := make([]byte, 16)
_, err := rand.Read(buf)
if err != nil {
panic(err) // out of randomness, should never happen
}
return fmt.Sprintf("%x", buf)
// or hex.EncodeToString(buf)
// or base64.StdEncoding.EncodeToString(buf)
}
Declaring Empty Slices
声明空 slice
,使用 var t []string
而不要使用 t := []string{}
,它们的区别在于前者为 nil
,后者为 empty
但是不为 nil
。
注:对 nil 进行 JSON 编码时,结果为 null。
Doc Comments
顶级导出包应该有文档注释。
Don’t Panic
不要使用 panic
作为普通的错误处理。
Error Strings
错误字符串不要大写或标点符号结尾,除非是专有名词或首字母缩写开头。
Examples
一个新的包应该包含运行列子。
Goroutine Lifetimes
要确保你所创建的 Goroutine
何时结束,垃圾回收器不会回收 goroutine
。
要确保并发代码简单并且生命周期容易观察,如果做不到使用文档进行说明。
Handle Errors
要处理每个函数的错误或返回错误。
Imports
导包应该避免名称冲突,如果发生重命名本地包或特定项目导入。
包的导入应该是有组织性的,通常标准库应该在第一行。
习惯:
第三方包放入第二行。
Import Blank
仅在 main 包 ,或 test 包 需要导入。
特殊情况导入其他位置请注释进行说明。
Import Dot
使用 .
在测试中解决循环引用,除此之外不要使用。
In-Band Errors
使用多返回值来处理错误。
Indent Error Flow
错误流处理
// not good
if err != nil {
// error handling
} else {
// normal code
}
// good
if err != nil {
// error handling
return // or continue, etc.
}
// normal code
// not good
if x, err := f(); err != nil {
// error handling
return
} else {
// use x
}
// good
x, err := f()
if err != nil {
// error handling
return
}
// use x
Initialisms
字母缩写:普通单词首字母大写,专有名词全部大写。
Interfaces
// TODO
Line Length
// TODO
Mixed Caps
采用驼峰命名。
Nacked Returns
Package Comments
//TODO
Package Names
包名应该见名知其意,若一个单词表示不了就建立成目录形式。
Pass Values
// TODO
Receiver Names
接收者的名字最好控制在一个或两个小写字母内。
Receiver Type
在方法上使用什么类型进行接受是比较困难的,在不确定的情况下使用指针作为接收者,有以下情况需要注意。
- 若接收者是 map , func ,chan 类型不要使用指针。
- 若方法需要修改接收方,则需要使用指针。
- 若接收者是结构体并且包含了 sync.Mutex 或相似的同步字段,则需要使用指针接收者。
- 若接收者是一个比较大的结构体或 slice ,使用指针接收者会更高效。对与大的定义可以将其内部字段或元素作为函数的参数,若觉得太多了则说明需要使用指针接收者。
- …
Synchronous Functions
应当尽可能使用同步函数,如直接调用或回调方式。若使用了异步方式,一定要确保协程泄漏问题。
Userful Test Failures
在测试代码中,失败的信息中应该写明详细内容。
if got != tt.want {
t.Errorf("Foo(%q) = %d; want %d", tt.in, got, tt.want) // or Fatalf, if test can't test anything more past this point
}
Variable Names
变量名称应该简单而符合单词所表示的意思。
例: c
优于 lineCount
, i
优于 sliceIndex
。
参考
版本日志
- 第一版:2021 年 03 月 31 日