[TOC]
和其它语言一样,名字在Go中是非常重要的。它们甚至还具有语义的效果:一个名字在程序包之外的可见性是由它的首字符是否为大写来确定的。因此,值得花费一些时间来讨论Go程序中的命名约定。
## 程序包名
当一个程序包被导入,程序包名便可以用来访问它的内容。在
~~~
import "bytes"
~~~
之后,导入的程序包便可以谈到`bytes.Buffer`。如果每个使用程序包的人都可以使用相同的名字来引用它的内容,这会是 很有帮助的。这意味着程序包名要很好:简短,简明,能引起共鸣的。按照惯例,程序包使用小写,一个单词的名字;不需要使用下划线或者混合大小写。要力求简 短,因为每个使用你的程序包的人都将敲入那个名字。不用担心会与*先前的*有冲突。程序包名只是导入的缺省名字;其不需要在所有源代码中是唯一的。对于很少出现的冲突情况下,导入的程序包可以选择一个不同的名字在本地使用。不管怎样,冲突是很少的,因为导入的文件名确定了所要使用的程序包。
另一种约定是,程序包名为其源目录的基础名;在`src/pkg/encoding/base64`中的程序包,是作为`"encoding/base64"`来导入的,但是名字为`base64`,而不是`encoding_base64`或`encodingBase64`。
程序包的导入者将使用名字来引用其内容,因此在程序包中被导出的名字可以利用这个事实来避免口吃现象。(不要使用`import .`标记,这将会简化那些必须在程序包之外运行,本不应该避免的测试)例如,在`bufio`程序包中的带缓冲的读入类型叫做`Reader`,而不是`BufReader`,因为用户看到的是`bufio.Reader`,一个清晰,简明的名字。而且,因为被导入的实体总是通过它们的程序包名来寻址,所以`bufio.Reader`和`io.Reader`并不冲突。类似的,为`ring.Ring`创建一个新实例的函数—在Go中是定义一个*构造器*—通常会被叫做`NewRing`,但是由于`Ring`是程序包导出的唯一类型,由于程序包叫做`ring`,所以它只叫做`New`。这样,程序包的客户将会看到`ring.New`。使用程序包结构可以帮助你选择好的名字。
另一个小例子是`once.Do`;`once.Do(setup)`很好读,写成`once.DoOrWaitUntilDone(setup)`并不会有所改善。长名字并不会自动使得事物更易读。具有帮助性的文档注释往往会比格外长的名字更有用。
## Get方法
Go不提供对Get方法和Set方法的自动支持。你自己提供Get方法和Set方法是没有错的,通常这么做是合适的。但是,在Get方法的名字中加上`Get`,是不符合语言习惯的,并且也没有必要。如果你有一个域叫做`owner`(小写,不被导出),则Get方法应该叫做`Owner`(大写,被导出),而不是`GetOwner`。对于要导出的,使用大写名字,提供了区别域和方法的钩子。Set方法,如果需要,则可以叫做`SetOwner`。这些名字在实际中都很好读:
~~~
owner := obj.Owner()
if owner != user {
obj.SetOwner(user)
}
~~~
## 接口名
按照约定,单个方法的接口使用方法名加上“er”后缀来命名,或者类似的修改来构造一个施动者名词:`Reader`,`Writer`,`Formatter`,`CloseNotifier`等。
有许多这样的名字,最有效的方式就是尊重它们,以及它们所体现的函数名字。`Read`,`Write`,`Close`,`Flush`,`String`等,都具有规范的签名和含义。为了避免混淆,不要为你的方法使用这些名字,除非其具有相同的签名和含义。反过来讲,如果你的类型实现了一个和众所周知的类型具有相同含义的方法,那么就使用相同的名字和签名;例如,为你的字符串转换方法起名为`String`,而不是`ToString`。
## 混合大小写
最后,Go约定使用`MixedCaps`或者`mixedCaps`的形式,而不是下划线来书写多个单词的名字。