go 项目 cmd目录_Golang 项目布局浅析
奇技 · 指南
Golang作為當下云開發中最為流行的語言之一,越來越受到廣大程序員的青睞。開發Golang項目經常遇到的一個常見問題是如何組織項目結構布局。今天作者從項目結構以及對內部、外部包的引用來講講布局問題,希望對大家有所幫助。
開始編碼之前,我們需要先明確一些問題:項目結構如何反映代碼的引入方式?
除代碼外,如何組織項目的命令行工具?
如何靈活的在不同模塊間組織項目代碼?
- 多個包如何在一個模塊中共存?
我們先明確一些名詞和概念:
Internal packages,內部私有包,只能從其模塊中的其他包引入,不能被外部包引入。用戶可以使用 go get 安裝需要的外部包。
1Helloworld
我們打開一個項目,項目路徑是模塊名。項目的 go.mod 文件包含以下行:
module github.com/qidian/modlibGo項目通常通過其GitHub路徑命名。Go還支持自定義名稱,本文暫不贅述,之后開新帖再說。我們可以暫時用`github.com/your-handle/your-project`或`your-project-domain.io`替換`github.com/qidian/modlib`。模塊名稱非常重要,因為他是項目代碼中引入包名的基礎:
2
項目布局
先來看一個項目 modlib 的目錄和文件布局:
├── LICENSE├── README.md├── config.go├── go.mod├── go.sum├── clientlib│ ├── lib.go│ └── lib_test.go├── cmd│ ├── modlib-client│ │ └── main.go│ └── modlib-server│ └── main.go├── internal│ └── auth│ ├── auth.go│ └── auth_test.go└── serverlib └── lib.go讓我們從根目錄中的文件開始。
go.mod 是模塊定義文件。它包含上面顯示的模塊名稱,我的項目沒有依賴項。依賴項與項目布局設計無關。有需要的同學可以從 Golang 官方博客學習。go.sum 由 go tools 管理,其包含所有依賴項校驗值。config.go,這是我們查看的第一個代碼文件,它包含一個簡單的?Config()函數:
package modlibfunc Config() string {return "modlib config"}第一行申明包名,由于該文件位于模塊的頂層,因此其程序包名稱即為模塊名稱。
關于如何引入?github.com/qidian/modlib?,我們來看一個例子:
package mainimport "fmt"import "github.com/qidian/modlib"func main() { fmt.Println(modlib.Config())}因此,如果您的模塊提供單個 package,或者您要從模塊的頂層軟件包中導出代碼,則將其所有代碼放在模塊的頂層目錄中,并命名該 package 作為模塊路徑的最后一部分(除非您使用更靈活的 vanity imports)。3
引用外部包
clientlib / lib.go 是我們對 clientlib 模塊封裝的文件。文件名可以根據業務邏輯來命名:
package clientlibfunc Hello() string {return "clientlib hello"}我們再來看下面這個例子,通過 github.com/qidian/modlib/clientlib 導入 clientlib:
package mainimport "fmt"import "github.com/qidian/modlib"import "github.com/qidian/modlib/clientlib"func main() { fmt.Println(modlib.Config()) fmt.Println(clientlib.Hello())}serverlib目錄包含了另一個用戶可以引入的package。這里展示了多個程序包如何在代碼結構中并存。關于包嵌套,它可以根據需要增加目錄層級。我們可見的? package 名稱由模塊根目錄的相對路徑確定。例如,如果我們有一個 `clientlib/tokens` 的子目錄 ,并在tokens包中包含一些代碼,則用戶將使用如下代碼引入該目錄。
import "github.com/qidian/modlib/clientlib/tokens“對于一些模塊而言,一個頂級 package 就足夠業務開發了。在本例中沒有用戶可導入的 package 子目錄,但是所有代碼都在 modlib 的單個或多個 Go 文件中。
4
Commands
一些Go項目還需要制作可執行程序,我們一般會再增加一個cmd目錄。該目錄是項目所有命令行程序的常規位置。程序的命名方案通常為:
用戶可以使用go工具按如下方式安裝此類命令:$ go get github.com/qidian/modlib/cmd/cmd-name# Go downloads, builds and installs cmd-name into the default location.# The bin/ directory in the default location is often in $PATH, so we can#?just?invoke?cmd-name?now$ cmd-name ...在modlib中,提供了兩個不同的命令行程序作為示例:modlib-client和modlib-server。在每個代碼中,代碼都在包main中;文件名為main.go。
這是我們在測試環境上運行的命令:$ go get github.com/qidian/modlib/cmd/modlib-client$ modlib-clientRunning clientConfig: modlib configclientlib hello$ go get github.com/qidian/modlib/cmd/modlib-server$ modlib-serverRunning serverConfig: modlib configAuth: thou art authorizedserverlib hello# Clean up...$ rm -f `which modlib-server` `which modlib-client`我們來看看 modlib-serve.go 是如何從 modlib 中導入其他代碼的:
package mainimport (??"fmt""github.com/qidian/modlib""github.com/qidian/modlib/internal/auth""github.com/qidian/modlib/serverlib")func main() { fmt.Println("Running server") fmt.Println("Config:", modlib.Config()) fmt.Println("Auth:", auth.GetAuth()) fmt.Println(serverlib.Hello())}Golang 里的絕對導入適用于引入package和二進制命令,這是 clientlib 中的代碼需要引入 modlib 時的例子:
github.com/eliben/modlib4
私有包
另一個重要概念是私有包,也就是項目內部使用的軟件包,并且我們不想導出給外部用戶。由于語義版本控制,這在Go模塊中尤其重要。您的項目在v1中導出的所有內容都將成為公共API,并且必須遵守語義版本兼容性。Go工具將內部包識別為特殊路徑,只有同一模塊中的軟件包可以引入它。如果我們嘗試在外部模塊代碼中引用,則會拋錯:
use of internal package github.com/eliben/modlib/internal/auth not allowed
在本文樣例中,internal中只有一個package。而在實際的工程項目里通常會有一堆完整的package目錄樹。
將內部API重構并將其導出給其他同學很容易,但是使用外部API并取消導出會很麻煩。所以我在開發時會盡可能地將模塊需要的私有包和代碼放入內部包中。最后再舉個例子,如果一個網站項目 repo 中,我們將代碼安排在 internal/website中。用于項目的內部工具和腳本也是如此。這樣一來項目的根目錄是最清晰并且對開發者來說更友好。理想情況下,開發者通過項目代碼布局就可以大致了解他們想了解的東西所在位置,因此將一些代碼放在內部會很有意義。相關文章
https://blog.golang.org/v2-go-modules
https://blog.golang.org/module-compatibility
TensorNet——基于TensorFlow的大規模稀疏特征模型分布式訓練框架
一種通過云配置處理應用權限彈框的方案
360Stack裸金屬服務器部署實踐
360技術公眾號
技術干貨|一手資訊|精彩活動
掃碼關注我們總結
以上是生活随笔為你收集整理的go 项目 cmd目录_Golang 项目布局浅析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: uat环境是什么环境_环境污染会对环境造
- 下一篇: golang string 转换 uin