gopl-zh.github.com/ch10/ch10-06.md
2017-08-24 22:30:56 +08:00

2.9 KiB
Raw Blame History

10.6. 包和命名

在本节中我们将提供一些关于Go语言独特的包和成员命名的约定。

当创建一个包一般要用短小的包名但也不能太短导致难以理解。标准库中最常用的包有bufio、bytes、flag、fmt、http、io、json、os、sort、sync和time等包。

它们的名字都简洁明了。例如不要将一个类似imageutil或ioutilis的通用包命名为util虽然它看起来很短小。要尽量避免包名使用可能被经常用于局部变量的名字这样可能导致用户重命名导入包例如前面看到的path包。

包名一般采用单数的形式。标准库的bytes、errors和strings使用了复数形式这是为了避免和预定义的类型冲突同样还有go/types是为了避免和type关键字冲突。

要避免包名有其它的含义。例如2.5节中我们的温度转换包最初使用了temp包名虽然并没有持续多久。但这是一个糟糕的尝试因为temp几乎是临时变量的同义词。然后我们有一段时间使用了temperature作为包名显然名字并没有表达包的真实用途。最后我们改成了和strconv标准包类似的tempconv包名这个名字比之前的就好多了。

现在让我们看看如何命名包的成员。由于是通过包的导入名字引入包里面的成员例如fmt.Println同时包含了包名和成员名信息。因此我们一般并不需要关注Println的具体内容因为fmt包名已经包含了这个信息。当设计一个包的时候需要考虑包名和成员名两个部分如何很好地配合。下面有一些例子

bytes.Equal    flag.Int    http.Get    json.Marshal

我们可以看到一些常用的命名模式。strings包提供了和字符串相关的诸多操作

package strings

func Index(needle, haystack string) int

type Replacer struct{ /* ... */ }
func NewReplacer(oldnew ...string) *Replacer

type Reader struct{ /* ... */ }
func NewReader(s string) *Reader

包名strings并没有出现在任何成员名字中。因为用户会这样引用这些成员strings.Index、strings.Replacer等。

其它一些包可能只描述了单一的数据类型例如html/template和math/rand等只暴露一个主要的数据结构和与它相关的方法还有一个以New命名的函数用于创建实例。

package rand // "math/rand"

type Rand struct{ /* ... */ }
func New(source Source) *Rand

这可能导致一些名字重复例如template.Template或rand.Rand这就是为什么这些种类的包名往往特别短的原因之一。

在另一个极端还有像net/http包那样含有非常多的名字和种类不多的数据类型因为它们都是要执行一个复杂的复合任务。尽管有将近二十种类型和更多的函数但是包中最重要的成员名字却是简单明了的Get、Post、Handle、Error、Client、Server等。