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