翻译: Effective Go (2)
本文是 Effective Go 的第二篇翻译,对应的章节为:Names,Semicolons
第一篇翻译[在这里](https://xabc.site/post/traeffectivego/),对应的章节为:Introduction, Formatting, Commentary.
第三篇翻译[在这里](https://xabc.site/post/traeffectivego3/),对应的章节为:Control structures
第四篇翻译[在这里](https://xabc.site/post/traeffectivego4/),对应的章节为:Functions.
第五篇翻译[在这里](https://xabc.site/post/traeffectivego5/),对应的章节为:Data.
第六篇翻译[在这里](https://xabc.site/post/traeffectivego6/),对应的章节为:Initialization, Methods.
第七篇翻译[在这里](https://xabc.site/post/traeffectivego7/),对应的章节为:Interfaces and other types,The blank identifier.
命名
命名在 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。在实践中,这样的命名习惯可读性比较强:
接口名字
按照习惯,只有一种方法的接口名称应该以该方法的名称加上-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)的左括号放到下一行,如果这么做了,(词法分析器会自动)在括号前插入分号,这会造成意想不到的结果。你应该这么写:
而不能写成这样:
版权声明: 本文为 InfoQ 作者【申屠鹏会】的原创文章。
原文链接:【http://xie.infoq.cn/article/d6e0314f725200ec4836a33a2】。文章转载请联系作者。
评论