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 日

赏
  目录