计算机科学中只有两件难事:缓存失效和命名。——Phil Karlton,Netscape架构师
命名是编程语言的要求,但是好的命名却是为了提高程序的可读性和可维护性。好的命名是什么样子的呢?Go语言的贡献者和布道师Dave Cheney给出了一个说法:“一个好笑话,如果你必须解释它,那就不好笑了。好的命名也类似。”无论哪门编程语言,良好的命名都应该遵循一些通用的原则,但就像之前提到的“语言影响思维”的假说那样,不同的编程语言会有一些个性化的命名惯例。
Go的设计哲学之一就是追求简单,它在命名上一样秉承着简单的总体原则。
要想做好Go标识符的命名(包括对包的命名),至少要遵循两个原则:简单且一致;利用上下文辅助命名。
7.1 简单且一致
- 包 对于Go中的包(package),一般建议以小写形式的单个单词命名。 在Go中,包名可以不唯一。 Go语言建议,包名应尽量与包导入路径(import path)的最后一个路径分段保持一致:比如:包导入路径golang.org/x/text/encoding的最后路径分段是encoding,该路径下包名就应该为encoding。 此外,我们在给包命名的时候,不仅要考虑包自身的名字,还要兼顾该包导出的标识符(如变量、常量、类型、函数等)的命名。由于对这些包导出标识符的引用必须以包名为前缀,因此对包导出标识符命名时,在名字中不要再包含包名,比如: strings.Reader good strings.StringReader bad bytes.Buffer good bytes.ByteBuffer bad
- 变量、类型、函数和方法
一个Go工程中包的数量是有限的,变量、类型、函数和方法的命名占据了命名工作的较大比重。
在Go中变量分为包级别的变量和局部变量(函数或方法内的变量)。函数或方法的参数、返回值都可以被视为局部变量。
Go语言官方要求标识符命名采用驼峰命名法(CamelCase),以变量名为例,如果变量名由一个以上的词组合构成,那么这些词之间紧密相连,不使用任何连接符(如下划线)。驼峰命名法有两种形式:一种是第一个词的首字母小写,后面每个词的首字母大写,叫作“小骆峰拼写法”(lowerCamelCase),这也是在Go中最常见的标识符命名法;而第一个词的首字母以及后面每个词的首字母都大写,叫作“大驼峰拼写法”(UpperCamelCase),又称“帕斯卡拼写法”(PascalCase)。由于首字母大写的标识符在Go语言中被视作包导出标识符,因此只有在涉及包导出的情况下才会用到大驼峰拼写法。不过如果缩略词的首字母是大写的,那么其他字母也要保持全部大写,比如HTTP(Hypertext Transfer Protocol)、CBC(Cipher Block Chaining)等。
一般来说,Go标识符仍以单个单词作为命名首选。从Go标准库代码的不完全统计结果来看,不同类别标识符的命名呈现出以下特征:循环和条件变量多采用单个字母命名(具体见上面的统计数据);函数/方法的参数和返回值变量以单个单词或单个字母为主;由于方法在调用时会绑定类型信息,因此方法的命名以单个单词为主;函数多以多单词的复合词进行命名;类型多以多单词的复合词进行命名。除了上述特征,还有一些在命名时常用的惯例。
- 变量名字中不要带有类型信息
- userSlice []*User bad
- users []*User good
- 保持简短命名变量含义上的一致性 Go语言中有大量单字母、单个词或缩写命名的简短命名变量。 如:i,k,v,t,b中在go语言中大量使用
- 常量 在Go语言中,常量在命名方式上与变量并无较大差别,并不要求全部大写。只是考虑其含义的准确传递,常量多使用多单词组合的方式命名。
- 接口 在Go语言中,对于接口类型优先以单个单词命名。对于拥有唯一方法(method)或通过多个拥有唯一方法的接口组合而成的接口,Go语言的惯例是用“方法名 er”命名。如:writer,reader,closer go语言推荐尽量定义小接口,并通过接口组合的方式构建程序。
- 变量名字中不要带有类型信息
7.2 利用上下文辅助命名
Go在给标识符命名时还要考虑上下文环境的惯例,即在不影响可读性的前提下,兼顾一致性原则,尽可能地用短小的名字命名标识符。
例如在for循环中用i,v取代index和value。
代码语言:javascript复制 // bad
func RuneCount(buffer []byte) int {
runeCount := 0
for index := 0; index < len(buffer); index {
if buffer[index] == 0 {
index
}
runeCount
}
return runeCount
}
// good
func RuneCount2(buffer []byte) int {
count := 0
for i := 0; i < len(buffer); i {
if buffer[i] == 0 {
i
}
count
}
return count
}
7.3 总结
Go语言追求简单一致且利用上下文辅助名字信息传达的命名惯例。这种命名方式可以隐藏不必要的关系。