本文是Effective Go的第二篇翻译,对应的章节为:Names,Semicolons
第一篇翻译在这里,对应的章节为:Introduction, Formatting, Commentary.
第三篇翻译在这里,对应的章节为:Control structures
第四篇翻译在这里,对应的章节为:Functions.
第五篇翻译在这里,对应的章节为:Data.
第六篇翻译在这里,对应的章节为:Initialization, Methods.
第七篇翻译在这里,对应的章节为:Interfaces and other types,The blank identifier.
第八篇翻译在这里,对应的章节为:Embedding.

命名

命名在Go语言中与其他任何语言都一样重要。有时它们甚至影响语义:比如包的可见性就取决于其首字母是否为大写。因此,值得花一点时间讨论Go编程中的命名规则。

包名

导入包后,包的名称就成为包内容的访问器。比如:
import "bytes"
在执行上句之后,导入的包就可以访问bytes.Buffer了。如果每个使用包的人都可以使用相同的名称引用其内容,则对编程很有帮助,这也意味着包名应该设计得当:简短,精练,扼要。通常,包名应使用小写的单个单词名称,不需要下划线或驼峰式记法。err的简写就是因为每个使用包的人都会输入这个名称。而且不必担心引用次序的冲突。包名只是导入时的默认名称,它不必在所有源代码中都是唯一的,并且本地导入时万一发生冲突,可以选择一个别名进行引用。无论如何,包很难混淆,因为通过文件名可以决定包的使用。
另一个惯例是,包名应是其源码的路径。比如包:src/encoding/base64的包应作为encoding/base64导入,包名应为base64而不是encoding_base64或encodingBase64.
包的导入者应使用包名引用其内容,这样的话,包的导出名可以避免冲突。(不要使用import .,尽管这样可以简化必须在测试包之外运行的测试,但还是应该避免这么做)例如,在bufio包中的缓存读取器叫Reader,而不是BufRead,因为用户看作bufio.Reader,这是一个简洁明了的名称。此外 ,由于导入的实体总是使用包名寻址,因此bufio.Reader不会与io.Reader冲突。类似,用于创建ring.Ring新实例的函数(Ring是Go中构造函数的定义)通常被称为NewRing,但是由于Ring是包唯一导出的类型,并且该包叫ring,因此它可以只叫做New,跟在包后面,就像ring.New。使用包结构可以帮助用户选择合适的名称。
另一个简短的例子是*once.Do();once.Do()可读性很好,而once.doOrWaitUntilDone()*这样的长名就不会更好读。一个有用的文档注释通常比长名称更有价值。

Getter

Go没有自动支持getter和setter。通常你可以自己提供getter和setter,但是将Get用作getter的名称既不符合习惯也没有这个必要。如果你有名为owner(小写字母,未导出)的字段,则getter方法名应为Owner(大写字母开头,导出),而不是GetOwner。如果需要setter,那通常可以命名为SetOwner。在实践中,这样的命名习惯可读性比较强:

owner := obj.Owner()
if owner != user {
    obj.SetOwner(user)
}

接口名字

按照习惯,只有一种方法的接口名称应该以该方法的名称加上-er后缀来命名。如Reader,Writer,Formatter,CloseNotifier 等。
此类的命名很多,遵循这样的命名非常有用。Read,Write,Close,Flush,String等具有规范的签名和意义。为避免混淆,除非你的方法具有相同的签名和意义,否则不要给他们使用任何名称。相反,如果你的类型实现的方法的含义与熟知类型上的方法的含义相同,请赋予相同的名称和签名。请将字符串转换方法命名为String而非ToString。

驼峰命名

最后,Go中约定使用驼峰而不是下划线来编写多个单词组成的命名。

分号

和C一样,在Go的正式语法中,分号用来分格语句,但是不同于C,分号不会在源码中真的出现。相反,词法分析器会使用一条简单的规则在扫描源码时自动插入分号,因此实际的源码中几乎没有分号。
插入的规则是这样的,如果换行符前的最后一个标记是标识符(包括int和float64之类的单词),数值或字符串常量之类,或以下标记之一:
break continue fallthrough return ++ -- ) }
词法分析器总会在这些标识符后插入分号。可以这么总结:如果换行符位于结束语句的标记之后,则插入分号。
在右括号之前的分号也是可以省略的,因此可以使用如下的语句:
go func() { for { dst <- <-src } }()
通常,Go只在诸如for循环,分隔初始化器,条件语句和延长语句情况下使用分号,如果在一行中写多个语句,那么也需要使用分号。
分号自动插入的一个后果是,你不能将一个控制结构(if, for, switch, select)的左括号放到下一行,如果这么做了,(词法分析器会自动)在括号前插入分号,这会造成意想不到的结果。你应该这么写:

if i < f() {
    g()
}

而不能写成这样:

if i < f()  // wrong!
{           // wrong!
    g()
}