Go编码规范

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

Named Result Parameters

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

参考

Go Code Review Comments

Effective Go

版本日志

  • 第一版:2021 年 03 月 31 日

  目录