写点什么

翻译: Effective Go (2)

用户头像
申屠鹏会
关注
发布于: 2020 年 04 月 23 日

本文是 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。在实践中,这样的命名习惯可读性比较强:

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()}
复制代码


发布于: 2020 年 04 月 23 日阅读数: 57
用户头像

申屠鹏会

关注

enjoy~ 2018.11.08 加入

https://xabc.site

评论

发布
暂无评论
翻译: Effective Go (2)