Go 语言编码风格指南
在Go语言官方提供的Effective Go的基础之上,我们制定了如下的编码规范作为补充。
注释
在注释文本和斜线之间插入一个空格
像这样:
// This is a comment
不要这样:
//This is a comment
用于代码生成的指令不需要遵循这个规则:
//go:generate go run gen.go
另外,临时注释代码也不需要添加空格,并且这些注释应该在提交之前删除。
为顶层的导出的名字添加文档注释
// Mathematical constants.
const Pi = 3.1415925
命名
Error 变量命名
像这样:
// 包级别导出的变量
var ErrSomthing = errors.New("something wenti wrong")
func main() {
// 通常将错误变量命名为 err
result, err := doSomething()
// 在你认为必要的时候,也可以使用一个更长的名字
var specificError error
result, specificError = doSpecificThing()
}
不要这样:
var ErrorSomething = errors.New("something went wrong")
var SomethingErr = errors.New("something went wrong")
var SomethingError = errors.New("something went wrong")
func main() {
var specificErr error
result, specificErr = doSpecificThing()
var errSpecific error
result, errSpecific = doSpecificThing()
var errorSpecific error
result, errorSpecific = doSpecificThing()
}
注意,错误消息应该用小写字母开头的字符串,因为这些消息可能会与其他内容拼接。
对于有多个大写字母的单词或专名,小写全部字母
像这样:
// 导出的变量
var OAuthEnabled bool
var GitHubToken string
// 未导出的变量,小写第一个单词的全部字母
var oauthEnabled bool
var githubToken string
不要这样:
// 未导出的变量
var oAuthEnabled bool
var gitHubToken string
使用单数形式的仓库和文件夹名称
像这样:
github.com/golang/example/hello
github.com/golang/example/outyet
golang.org/x/mobile/example/basic
golang.org/x/mobile/example/flappy
golang.org/x/image/...
github.com/shurcooL/tictactoe/player/bad
github.com/shurcooL/tictactoe/player/random
不要这样:
github.com/golang/examples/hello
github.com/golang/examples/outyet
golang.org/x/mobile/examples/basic
golang.org/x/mobile/examples/flappy
golang.org/x/images/...
github.com/shurcooL/tictactoe/players/bad
github.com/shurcooL/tictactoe/players/random
注意,example内的文件夹名称也是单数形式的。
切片
不要显式地初始化切片
像这样:
var users []string
不要这样:
users := []string{}
// Or
users := make([]string, 0)
使用len()检查切片是否为空
像这样:
if len(s) > 0 {
}
不要这样:
if s != nil && len(s) > 0 {
}
类似地,map
和channel
也可以使用len()
检查是否为空。
使用copy()
复制切片
像这样:
var s1, s2 []byte
// ...
copy(s2, s1)
不要这样:
var s1, s2 []byte
// ...
for i, v := range s1 {
s2[i] = v
}
for i := range s1 {
s2[i] = s1[i]
}
append
可以将字符串添加到字节切片
slice = append([]byte("hello "), "world"...)
字符串
空字符串检查
像这样:
if s == "" {
}
不要这样:
if len(s) == 0 {
}
虽然这两种写法都是正确的,但前一种写法的可读性更好。
随机数
不要使用math/rand生成密码
import (
"crypto/rand"
"fmt"
)
func Key() string {
buf := make([]byte, 16)
_, err := rand.Read(buf)
if err != nil {
panic(err)
}
return fmt.Sprintf("%x", buf)
}
错误处理
在适宜的地方使用error类型代替字符串
像这样:
func respondWithError(w http.ResponseWriter, code int, msg error) {
payload := map[string]string{"error": msg.Error()}
response, _ := json.Marshal(payload)
// ...
}
不要这样:
func respondWithError(w http.ResponseWriter, code int, msg string) {
payload := map[string]string{"error": msg}
response, _ := json.Marshal(payload)
// ...
}
包装你的错误
像这样:
func formatTimeWithMessage(hours, minutes int) (string, error) {
formatted, err := formatTime(hours, minutes)
if err != nil {
return "", fmt.Errorf("formatTimeWithMessage: %v", err)
}
// ...
}
不要这样:
func formatTimeWithMessage(hours, minutes int) (string, error) {
formatted, err := formatTime(hours, minutes)
if err != nil {
return "", err
}
// ...
}
当多个地方都有调用 formatTime 函数时,后者无法有效地定位错误来源。
不要使用panic进行普通的错误处理
TODO
不要忽略错误变量
TODO