Go语言代码建议

Go的简单性、可读性、生产力

标识符:

很简洁、具有描述性、可预测的【从名字推断出使用方式】

命名的时候需要考虑上下文的!例如我们方法参数中名字就能很好的代表!

变量或常量的名称应描述其目的,而不是内容的类型!而注解应该描述内容的,如

var userMap map[string]*User

这个声明有什么好处? 我们可以看到它是一个 map,它与 *User 类型有关。 但是 usersMap 是一个 map,而 Go 语言是一种静态类型的语言,如果没有定义变量,不会让我们意外地使用到它,因此 Map 后缀是多余的。

建议是避免使用任何类似变量类型的后缀。

贴士:
不要让包名窃取好的变量名。
导入标识符的名称包括其包名称。 例如,context 包中的 Context 类型将被称为 context.Context。 这使得无法将 context 用作包中的变量或类型。

func WriteLog(context context.Context, message string)

上面的栗子将会编译出错。 这就是为什么 context.Context 类型的通常的本地声明是 ctx,例如:

func WriteLog(ctx context.Context, message string)

一致的声明样式:声明变量但没有初始化时,请使用 var 当声明变量稍后将在函数中初始化时,请使用 var 关键字。

在没有初始化的情况下声明变量时,请使用 var 语法。

声明并初始化变量时,请使用 :=

贴士:
使复杂的声明显而易见。
当事情变得复杂时,它看起来就会很复杂。例如

var length uint32 = 0x80

这里 length 可能要与特定数字类型的库一起使用,并且 length 明确选择为 uint32 类型而不是短声明形式:

length := uint32(0x80)

在第一个例子中,我故意违反了规则, 使用 var 声明带有初始化变量的。 这个决定与我的常用的形式不同,这给读者一个线索,告诉他们一些不寻常的事情将会发生。

注释:变量或常量的名称应描述其目的。 向变量或常量添加注释时,该注释应描述变量内容,而不是变量目的。

贴士:
对于没有初始值的变量,注释应描述谁负责初始化此变量。

// sizeCalculationDisabled indicates whether it is safe
// to calculate Types' widths and alignments. See dowidth.
var sizeCalculationDisabled bool

这里的注释让读者知道 dowidth 函数负责维护 sizeCalculationDisabled 的状态。

隐藏在众目睽睽下
这个提示来自Kate Gregory[3]。有时你会发现一个更好的变量名称隐藏在注释中。

// registry of SQL drivers
var registry = make(map[string]*sql.Driver)

注释是由作者添加的,因为 registry 没有充分解释其目的 - 它是一个注册表,但注册的是什么?

通过将变量重命名为 sqlDrivers,现在可以清楚地知道此变量的目的是保存SQL驱动程序。

var sqlDrivers = make(map[string]*sql.Driver)

之前的注释就是多余的,可以删除。

在编写描述函数的注释,如果发现很难写出注释表示这段代码很难理解

包的设计:避免使用类似 basecommonutil 的包名称

当两个或多个实现共有的功能或客户端和服务器的常见类型被重构为单独的包时,通常会找到名称类似于 basecommon 的包。我相信解决方案是减少包的数量,将客户端,服务器和公共代码组合到一个以包的功能命名的包中。

例如,net/http 包没有 clientserver 的分包,而是有一个 client.goserver.go 文件,每个文件都有各自的类型,还有一个 transport.go 文件,用于公共消息传输代码。

贴士:
标识符的名称包括其包名称。
重要的是标识符的名称包括其包的名称。

  • 当由另一个包引用时,net/http 包中的 Get 函数变为 http.Get
  • 当导入到其他包中时,strings 包中的 Reader 类型变为 strings.Reader
  • net 包中的 Error 接口显然与网络错误有关。

项目结构:

通过 import 语句将代码排列到文件中

如果你按照包提供的内容来安排你的程序包,是否需要对 Go 包中的文件也执行相同的操作?什么时候应该将 .go 文件拆分成多个文件?什么时候应该考虑整合 .go 文件?

以下是我的经验法则:

  • 开始时使用一个 .go 文件。为该文件指定与文件夹名称相同的名称。例如: package http 应放在名为 http 的目录中名为 http.go 的文件中。
  • 随着包的增长,您可能决定将各种职责任务拆分为不同的文件。例如:messages.go 包含 RequestResponse 类型,client.go 包含 Client 类型,server.go包含 Server 类型。
  • 如果你的文件中 import 的声明类似,请考虑将它们组合起来。或者确定 import 集之间的差异并移动它们。
  • 不同的文件应该负责包的不同区域。messages.go 可能负责网络的 HTTP 请求和响应,http.go 可能包含底层网络处理逻辑,client.goserver.go 实现 HTTP 业务逻辑请求的实现或路由等等。

贴士: 首选名词为源文件命名。

注意:
Go编译器并行编译每个包。 在一个包中,编译器并行编译每个函数(方法只是 Go 语言中函数的另一种写法)。 更改包中代码的布局不会影响编译时间。