## 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
```
包名strings并沒有出現在任何成員名字中。因為用戶會這樣引用這些成員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等。
- 前言
- Go語言起源
- Go語言項目
- 本書的組織
- 更多的信息
- 致謝
- 入門
- Hello, World
- 命令行參數
- 查找重復的行
- GIF動畫
- 獲取URL
- 并發獲取多個URL
- Web服務
- 本章要點
- 程序結構
- 命名
- 聲明
- 變量
- 賦值
- 類型
- 包和文件
- 作用域
- 基礎數據類型
- 整型
- 浮點數
- 復數
- 布爾型
- 字符串
- 常量
- 復合數據類型
- 數組
- Slice
- Map
- 結構體
- JSON
- 文本和HTML模板
- 函數
- 函數聲明
- 遞歸
- 多返回值
- 錯誤
- 函數值
- 匿名函數
- 可變參數
- Deferred函數
- Panic異常
- Recover捕獲異常
- 方法
- 方法聲明
- 基于指針對象的方法
- 通過嵌入結構體來擴展類型
- 方法值和方法表達式
- 示例: Bit數組
- 封裝
- 接口
- 接口是合約
- 接口類型
- 實現接口的條件
- flag.Value接口
- 接口值
- sort.Interface接口
- http.Handler接口
- error接口
- 示例: 表達式求值
- 類型斷言
- 基于類型斷言識別錯誤類型
- 通過類型斷言查詢接口
- 類型分支
- 示例: 基于標記的XML解碼
- 補充幾點
- Goroutines和Channels
- Goroutines
- 示例: 并發的Clock服務
- 示例: 并發的Echo服務
- Channels
- 并發的循環
- 示例: 并發的Web爬蟲
- 基于select的多路復用
- 并發的退出
- 示例: 聊天服務
- 基于共享變量的并發
- 競爭條件
- sync.Mutex互斥鎖
- sync.RWMutex讀寫鎖
- 內存同步
- 競爭條件檢測
- 示例: 并發的非阻塞緩存
- Goroutines和線程
- 包和工具
- 包簡介
- 導入路徑
- 包聲明
- 導入聲明
- 包的匿名導入
- 包和命名
- 工具
- 測試
- go test
- 測試函數
- 測試覆蓋率
- 基準測試
- 剖析
- 示例函數
- 反射
- 為何需要反射?
- reflect.Type和reflect.Value
- Display遞歸打印
- 示例: 編碼S表達式
- 通過reflect.Value修改值
- 示例: 解碼S表達式
- 顯示一個類型的方法集
- 幾點忠告
- 底層編程
- unsafe.Sizeof, Alignof 和 Offsetof
- unsafe.Pointer
- 示例: 深度相等判斷
- 通過cgo調用C代碼
- 幾點忠告
- 附錄
- 附錄A:原文勘誤
- 附錄B:作者譯者
- 附錄C:譯文授權
- 附錄D:其它語言