## 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包提供了和字符串相關的諸多操作：

```Go
package strings

func Index(needle, haystack string) int

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

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

字符串string本身併沒有出現在每個成員名字中。因爲用戶會這樣引用這些成員strings.Index、strings.Replacer等。

其它一些包，可能隻描述了單一的數據類型，例如html/template和math/rand等，隻暴露一個主要的數據結構和與它相關的方法，還有一個以New命名的函數用於創建實例。

```Go
package rand // "math/rand"

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

這可能導致一些名字重複，例如template.Template或rand.Rand，這就是爲什麽這些種類的包名往往特别短的原因之一。

在另一個極端，還有像net/http包那樣含有非常多的名字和種類不多的數據類型，因爲它們都是要執行一個複雜的複合任務。盡管有將近二十種類型和更多的函數，但是包中最重要的成員名字卻是簡單明了的：Get、Post、Handle、Error、Client、Server等。
