Go 部落格
組織 Go 程式碼
引言
Go 程式碼的組織方式與其他語言不同。本文討論瞭如何為您的 Go 程式中的元素命名和打包,以最好地服務於使用者。
選擇好的名稱
您選擇的名稱會影響您對程式碼的思考方式,因此在為包及其匯出的識別符號命名時要多加註意。
包的名稱為其內容提供了上下文。例如,標準庫中的 bytes 包匯出了 Buffer
型別。僅憑 Buffer
這個名稱並不具有很強的描述性,但與其包名稱結合後,其含義就變得清晰了:bytes.Buffer
。如果該包的名稱不夠描述性,例如 util
,那麼緩衝區很可能會獲得一個更長、更笨拙的名稱 util.BytesBuffer
。
在工作中,不要害怕重新命名事物。隨著您對程式的投入時間的增加,您將更好地理解其各個部分如何協同工作,因此也更清楚它們的名稱應該是什麼。沒有必要過早地鎖定您的決定。(gofmt 命令有一個 -r
標誌,它提供了一種語法感知的搜尋和替換功能,使大規模重構更加容易。)
一個好的名稱是軟體介面最重要的部分:名稱是程式碼的每個使用者首先看到的東西。因此,精心選擇的名稱是良好文件的起點。以下許多實踐都源於良好的命名。
選擇好的匯入路徑(使您的包“go get”-able)
匯入路徑是使用者匯入包的字串。它指定了包的原始碼所在的目錄(相對於 $GOROOT/src/pkg
或 $GOPATH/src
)。
匯入路徑應該是全域性唯一的,因此請使用您的原始碼儲存庫的路徑作為其基礎。例如,來自 go.net
子儲存庫的 websocket
包的匯入路徑是 "golang.org/x/net/websocket"
。Go 專案擁有 "github.com/golang"
這個路徑,因此其他作者不能為不同的包使用該路徑。因為儲存庫 URL 和匯入路徑是一致的,所以 go get
命令可以自動獲取和安裝該包。
如果您不使用託管的原始碼儲存庫,請選擇一個唯一的自定義字首,例如域名、公司或專案名稱。例如,所有 Google 內部 Go 程式碼的匯入路徑都以字串 "google"
開頭。
匯入路徑的最後一個元素通常與包名相同。例如,匯入路徑 "net/http"
包含包 http
。這不是強制要求——如果您願意,也可以讓它們不同——但為了可預測性,您應該遵循約定:使用者可能會驚訝於匯入 "foo/bar"
會在包名稱空間中引入識別符號 quux
。
有時人們會將 GOPATH
設定為其原始碼儲存庫的根目錄,並將他們的包放在相對於儲存庫根目錄的目錄中,例如 "src/my/package"
。一方面,這可以縮短匯入路徑("my/package"
而不是 "github.com/me/project/my/package"
),但另一方面,這會破壞 go get
,並迫使使用者在嘗試使用該包時重新設定他們的 GOPATH
。不要這樣做。
最小化匯出的介面
您的程式碼很可能由許多有用的小程式碼片段組成,因此很容易將大部分功能暴露在您包的匯出介面中。抵制這種衝動!
您提供的介面越大,您就越需要支援。使用者很快就會依賴您匯出的每一個型別、函式、變數和常量,從而建立一個隱式的契約,您必須永遠遵守,否則就有可能破壞使用者的程式。在準備 Go 1 時,我們仔細審查了標準庫的匯出介面,並刪除了我們尚未準備好承諾的部分。您在分發自己的庫時也應該同樣謹慎。
如有疑問,請省略!
將什麼放入包中
將所有內容都扔進一個“雜貨包”式的包很容易,但這會稀釋包名稱的含義(因為它必須涵蓋大量功能),並迫使使用者使用包的小部分功能時,需要編譯和連結大量不相關的程式碼。
另一方面,將程式碼拆分成太多小的包也很容易,這樣您可能會陷入介面設計的泥潭,而不是僅僅完成工作。
以 Go 標準庫為例。它的一些包很大,一些包很小。例如,http 包包含 17 個 go 原始檔(不包括測試),並匯出了 109 個識別符號;而 hash 包由一個檔案組成,只匯出了三個宣告。沒有一成不變的規則;兩種方法在特定情況下都是合適的。
也就是說,main
包通常比其他包要大。複雜的命令包含大量在可執行檔案上下文之外用處不大的程式碼,通常將所有程式碼放在同一個地方更簡單。例如,go 工具超過 12000 行程式碼,分佈在 34 個檔案中。
記錄您的程式碼
良好的文件是可用且可維護程式碼的基本品質。請閱讀 Godoc:文件化 Go 程式碼一文,瞭解如何編寫良好的文件註釋。
下一篇文章:App Engine 1.7.1 中的 Go 更新
上一篇文章:GCC 4.7.1 中的 Gccgo
部落格索引