Go Best Practices

包名

当命名包时,请按下面规则选择一个名称:

全部小写。没有大写或下划线。

大多数使用命名导入的情况下,不需要重命名。

简短而简洁。请记住,在每个使用的地方都完整标识了该名称。

不用复数。例如net/url,而不是net/urls。

不是“common”,“util”,“shared”或“lib”。这些是不好的,信息量不足的名称。

另请参阅Go包名称Go包样式指南

函数名

我们遵循Go社区关于使用MixedCaps作为函数名的约定。有一个例外,为了对相关的测试用例进行分组,函数名可能包含下划线,如: TestMyFunction_WhatIsBeingTested。

包导入别名

如果程序包名称与导入路径的最后一个元素不匹配,则必须使用导入别名。

import (

“net/http”

client “example.com/client-go

trace “example.com/trace/v2

)

在所有其他情况下,除非导入之间有直接冲突,否则应避免导入别名。

Bad

import (

“fmt”

“os”

nettrace “golang.net/x/trace

)

vs.

Good

import (

“fmt”

“os”

“runtime/trace”

nettrace “golang.net/x/trace

)

函数分组与顺序

函数应按粗略的调用顺序排序。

同一文件中的函数应按接收者分组。

因此,导出的函数应先出现在文件中,放在struct、const和var定义的后面。

在定义类型之后,但在接收者的其余方法之前,可能会出现一个newXYZ()/ NewXYZ()。

由于函数是按接收者分组的,因此普通工具函数应在文件末尾出现。

Bad

func (s *something) Cost() {

return calcCost(s.weights)

}

type something struct{ … }

func calcCost(n int[]) int {…}

func (s *something) Stop() {…}

func newSomething() *something {

return &something{}

}

vs.

Good

type something struct{ … }

func newSomething() *something {

return &something{}

}

func (s *something) Cost() {

return calcCost(s.weights)

}

func (s *something) Stop() {…}

func calcCost(n int[]) int {…}

减少嵌套

代码应通过尽可能先处理错误情况/特殊情况并尽早返回或继续循环来减少嵌套。减少嵌套多个级别的代码的代码量。

Bad

for _, v := range data {

if v.F1 == 1 {

v = process(v)

if err := v.Call(); err == nil {

  v.Send()

} else {

  return err

}

} else {

log.Printf("Invalid v: %v", v)

}

}

vs.

Good

for _, v := range data {

if v.F1 != 1 {

log.Printf("Invalid v: %v", v)

continue

}

v = process(v)

if err := v.Call(); err != nil {

return err

}

v.Send()

}

不必要的else

如果在if的两个分支中都设置了变量,则可以将其替换为单个if。

Bad

var a int

if b {

a = 100

} else {

a = 10

}

vs.

Good

a := 10

if b {

a = 100

}

顶层变量声明

在顶层,使用标准var关键字。请勿指定类型,除非它与表达式的类型不同。

Bad

var _s string = F()

func F() string { return “A” }

vs.

Good

var _s = F()

// 由于F已经明确了返回一个字符串类型,因此我们没有必要显式指定_s的类型

func F() string { return “A” }

如果表达式的类型与所需的类型不完全匹配,请指定类型。

type myError struct{}

func (myError) Error() string { return “error” }

func F() myError { return myError{} }

var _e error = F()

// F返回一个myError类型的实例,但是我们要error类型