亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

深入理解Go中的項目代碼布局

 更新時間:2023年11月07日 08:15:22   作者:賈維斯Echo  
Go?語言的創(chuàng)世項目其實就是?Go?語言項目自身,是全世界第一個?Go?語言項目,本文主要來和大家詳細介紹一下Go中的項目代碼布局,需要的可以了解下

一、Go 語言“創(chuàng)世項目”結(jié)構(gòu)

Go 語言的創(chuàng)世項目其實就是 Go 語言項目自身,是全世界第一個 Go 語言項目。

Go 1.5 版本實現(xiàn)自舉前,C 語言代碼行數(shù)也占據(jù)了 32.10%,在之后實現(xiàn)版本自舉后,Go 語言代碼行數(shù)占比將近 90%,C 語言比例下降為不到 1%。

在這個版本迭代過程中,Go 語言項目的布局結(jié)構(gòu)卻整體保留了下來。

Go 語言項目結(jié)構(gòu)布局對后續(xù) Go 社區(qū)的項目具有重要的參考價值,尤其是 Go 項目早期 src 目錄下面的結(jié)構(gòu)。

首先,我們從GitHub下載Go語言的源代碼:

 git clone http://github.com/golang/go.git

在進入 Go 語言項目的根目錄后,我們可以使用 “tree” 命令來查看該項目的初始源代碼結(jié)構(gòu)布局。以 Go 1.3 版本為例,查看結(jié)果如下所示:

$cd go // 進入Go語言項目根目錄
$git checkout go1.3 // 切換到go 1.3版本
$tree -LF 1 ./src // 查看src目錄下的結(jié)構(gòu)布局
./src
├── all.bash*
├── clean.bash*
├── cmd/
├── make.bash*
├── Make.dist
├── pkg/
├── race.bash*
├── run.bash*
... ...
└── sudo.bash*

1.1 src 目錄結(jié)構(gòu)三個特點

從上面的結(jié)果來看,src 目錄下面的結(jié)構(gòu)有這三個特點

1.**頂層腳本文件:**以 all.bash 為代表的代碼構(gòu)建的腳本源文件放在了 src 下面的頂層目錄下

2.可執(zhí)行文件目錄(cmd): src 下的二級目錄 cmd 下面存放著 Go 相關可執(zhí)行文件的相關目錄,我們可以深入查看一下 cmd 目錄下的結(jié)構(gòu):

cd cmd
tree .
# 看到如下結(jié)果
./cmd
... ...
├── 6a/
├── 6c/
├── 6g/
... ...
├── cc/
├── cgo/
├── dist/
├── fix/
├── gc/
├── go/
├── gofmt/
├── ld/
├── nm/
├── objdump/
├── pack/
└── yacc/

可以看到,這里的每個子目錄都是一個 Go 工具鏈命令或子命令對應的可執(zhí)行文件。其中,6a、6c、6g 等是早期 Go 版本針對特定平臺的匯編器、編譯器等的特殊命名方式。

3.**標準庫和運行時實現(xiàn)(pkg):**你會看到 src 下的二級目錄 pkg 下面存放著運行時實現(xiàn)、標準庫包實現(xiàn),這些包既可以被上面 cmd 下各程序所導入,也可以被 Go 語言項目之外的 Go 程序依賴并導入。下面是我們通過 tree 命令查看 pkg 下面結(jié)構(gòu)的輸出結(jié)果:

cd pkg
tree .
# 看到如下結(jié)果
./pkg
... ...
├── flag/
├── fmt/
├── go/
├── hash/
├── html/
├── image/
├── index/
├── io/
... ...
├── net/
├── os/
├── path/
├── reflect/
├── regexp/
├── runtime/
├── sort/
├── strconv/
├── strings/
├── sync/
├── syscall/
├── testing/
├── text/
├── time/
├── unicode/
└── unsafe/

這種源代碼結(jié)構(gòu)布局風格對后續(xù)許多 Go 項目的布局產(chǎn)生了影響,包括一些知名項目如 Go 調(diào)試器 Delve、容器技術(shù)項目 Docker,以及容器編排項目 Kubernetes,它們?nèi)匀槐3种愃频捻椖坎季诛L格。這種一致性有助于開發(fā)者更容易理解和導航不同 Go 項目的源代碼結(jié)構(gòu)。

二、Go 項目布局演進

當然,現(xiàn)在布局結(jié)構(gòu)也在一直在不斷地演化,簡單來說可以歸納為下面三個比較重要的演進。

2.1 演進一:Go 1.4 版本刪除 pkg 這一中間層目錄并引入 internal 目錄

Go 語言項目在其 1.4 版本中進行了源碼樹結(jié)構(gòu)的簡化和優(yōu)化,主要體現(xiàn)在以下兩個方面:

簡化源碼樹層次: Go 1.4 版本刪除了原有源碼樹中的 “src/pkg/xxx” 這一層級目錄,直接使用 “src/xxx” 的結(jié)構(gòu)。這一變化減少了源碼樹的深度,使得 Go 項目源碼更易于閱讀和探索。

引入 internal 包機制: Go 1.4 引入 internal 包機制,增加了 internal 目錄。這個 internal 機制其實是所有 Go 項目都可以用的,Go 語言項目自身也是自 Go 1.4 版本起,就使用 internal 機制了。根據(jù) internal 機制的定義,一個 Go 項目里的 internal 目錄下的 Go 包,只可以被本項目內(nèi)部的包導入。項目外部是無法導入這個 internal 目錄下面的包的??梢哉f,internal 目錄的引入,讓一個 Go 項目中 Go 包的分類與用途變得更加清晰。

2.2 演進二:Go1.6 版本增加 vendor 目錄

第二次的演進,其實是為了解決 Go 包依賴版本管理的問題,Go 核心團隊在 Go 1.5 版本中做了第一次改進。增加了 vendor 構(gòu)建機制,也就是 Go 源碼的編譯可以不在 GOPATH 環(huán)境變量下面搜索依賴包的路徑,而在 vendor 目錄下查找對應的依賴包。

Go 語言項目自身也在 Go 1.6 版本中增加了 vendor 目錄以支持 vendor 構(gòu)建,但 vendor 目錄并沒有實質(zhì)性緩存任何第三方包。直到 Go 1.7 版本,Go 才真正在 vendor 下緩存了其依賴的外部包。這些依賴包主要是 golang.org/x 下面的包,這些包同樣是由 Go 核心團隊維護的,并且其更新速度不受 Go 版本發(fā)布周期的影響。

vendor 機制與目錄的引入,讓 Go 項目第一次具有了可重現(xiàn)構(gòu)建(Reproducible Build)的能力。

2.3 演進三:Go 1.13 版本引入 go.mod 和 go.sum

第三次演進,還是為了解決 Go 包依賴版本管理的問題。在 Go 1.11 版本中,Go 核心團隊做出了第二次改進嘗試:引入了 Go Module 構(gòu)建機制,也就是在項目引入 go.mod 以及在 go.mod 中明確項目所依賴的第三方包和版本,項目的構(gòu)建就將擺脫 GOPATH 的束縛,實現(xiàn)精準的可重現(xiàn)構(gòu)建。

Go 語言項目自身在 Go 1.13 版本引入 go.mod 和 go.sum 以支持 Go Module 構(gòu)建機制,下面是 Go 1.13 版本的 go.mod 文件內(nèi)容:

module std

go 1.13

require (
  golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8
  golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7
  golang.org/x/sys v0.0.0-20190529130038-5219a1e1c5f8 // indirect
  golang.org/x/text v0.3.2 // indirect
)

我們看到,Go 語言項目自身所依賴的包在 go.mod 中都有對應的信息,而原本這些依賴包是緩存在 vendor 目錄下的。

總的來說,這三次演進主要體現(xiàn)在簡化結(jié)構(gòu)布局,以及優(yōu)化包依賴管理方面,起到了改善 Go 開發(fā)體驗的作用。可以說,Go 創(chuàng)世項目的源碼布局以及演化對 Go 社區(qū)項目的布局具有重要的啟發(fā)意義,以至于在多年的 Go 社區(qū)實踐后,Go 社區(qū)逐漸形成了公認的 Go 項目的典型結(jié)構(gòu)布局。

三、現(xiàn)在 Go 項目的典型結(jié)構(gòu)布局

Go 項目通常分為可執(zhí)行程序項目和庫項目,現(xiàn)在我們就來分析一下這兩類 Go 項目的典型結(jié)構(gòu)布局分別是怎樣的。

3.1 Go 可執(zhí)行程序項目的典型結(jié)構(gòu)布局

可執(zhí)行程序項目是以構(gòu)建可執(zhí)行程序為目的的項目,Go 社區(qū)針對這類 Go 項目所形成的典型結(jié)構(gòu)布局是這樣的:

$tree -F exe-layout 
exe-layout
├── cmd/
│   ├── app1/
│   │   └── main.go
│   └── app2/
│       └── main.go
├── go.mod
├── go.sum
├── internal/
│   ├── pkga/
│   │   └── pkg_a.go
│   └── pkgb/
│       └── pkg_b.go
├── pkg1/
│   └── pkg1.go
├── pkg2/
│   └── pkg2.go
└── vendor/

這樣的一個 Go 項目典型布局就是“脫胎”于 Go 創(chuàng)世項目的最新結(jié)構(gòu)布局,我現(xiàn)在跟你解釋一下這里面的幾個要點。

我們從上往下按順序來,先來看 cmd 目錄。cmd 目錄就是存放項目要編譯構(gòu)建的可執(zhí)行文件對應的 main 包的源文件。如果你的項目中有多個可執(zhí)行文件需要構(gòu)建,每個可執(zhí)行文件的 main 包單獨放在一個子目錄中,比如圖中的 app1、app2,cmd 目錄下的各 app 的 main 包將整個項目的依賴連接在一起。

而且通常來說,main 包應該很簡潔。我們在 main 包中會做一些命令行參數(shù)解析、資源初始化、日志設施初始化、數(shù)據(jù)庫連接初始化等工作,之后就會將程序的執(zhí)行權(quán)限交給更高級的執(zhí)行控制對象。另外,也有一些 Go 項目將 cmd 這個名字改為 app 或其他名字,但它的功能其實并沒有變。

接著我們來看 pkgN 目錄,這是一個存放項目自身要使用、同樣也是可執(zhí)行文件對應 main 包所要依賴的庫文件,同時這些目錄下的包還可以被外部項目引用。

然后是 go.mod 和 go.sum,它們是 Go 語言包依賴管理使用的配置文件。我們前面說過,Go 1.11 版本引入了 Go Module 構(gòu)建機制,這里我建議你所有新項目都基于 Go Module 來進行包依賴管理,因為這是目前 Go 官方推薦的標準構(gòu)建模式。

對于還沒有使用 Go Module 進行包依賴管理的遺留項目,比如之前采用 dep、glide 等作為包依賴管理工具的,建議盡快遷移到 Go Module 模式。Go 命令支持直接將 dep 的 Gopkg.toml/Gopkg.lock 或 glide 的 glide.yaml/glide.lock 轉(zhuǎn)換為 go.mod。

最后我們再來看看 vendor 目錄。vendor 是 Go 1.5 版本引入的用于在項目本地緩存特定版本依賴包的機制,在 Go Modules 機制引入前,基于 vendor 可以實現(xiàn)可重現(xiàn)構(gòu)建,保證基于同一源碼構(gòu)建出的可執(zhí)行程序是等價的。

不過呢,我們這里將 vendor 目錄視為一個可選目錄。原因在于,Go Module 本身就支持可再現(xiàn)構(gòu)建,而無需使用 vendor。 當然 Go Module 機制也保留了 vendor 目錄(通過 go mod vendor 可以生成 vendor 下的依賴包,通過 go build -mod=vendor 可以實現(xiàn)基于 vendor 的構(gòu)建)。一般我們僅保留項目根目錄下的 vendor 目錄,否則會造成不必要的依賴選擇的復雜性。

當然了,有些開發(fā)者喜歡借助一些第三方的構(gòu)建工具輔助構(gòu)建,比如:make、bazel 等。你可以將這類外部輔助構(gòu)建工具涉及的諸多腳本文件(比如 Makefile)放置在項目的頂層目錄下,就像 Go 創(chuàng)世項目中的 all.bash 那樣。

另外,這里只要說明一下的是,Go 1.11 引入的 module 是一組同屬于一個版本管理單元的包的集合。并且 Go 支持在一個項目 / 倉庫中存在多個 module,但這種管理方式可能要比一定比例的代碼重復引入更多的復雜性。 因此,如果項目結(jié)構(gòu)中存在版本管理的“分歧”,比如:app1 和 app2 的發(fā)布版本并不總是同步的,那么我建議你將項目拆分為多個項目(倉庫),每個項目單獨作為一個 module 進行單獨的版本管理和演進。

當然如果你非要在一個代碼倉庫中存放多個 module,那么新版 Go 命令也提供了很好的支持。比如下面代碼倉庫 multi-modules 下面有三個 module:mainmodule、module1 和 module2:

$tree multi-modules
multi-modules
├── go.mod // mainmodule
├── module1
│   └── go.mod // module1
└── module2
    └── go.mod // module2

我們可以通過 git tag 名字來區(qū)分不同 module 的版本。其中 vX.Y.Z 形式的 tag 名字用于代碼倉庫下的 mainmodule;而 module1/vX.Y.Z 形式的 tag 名字用于指示 module1 的版本;同理,module2/vX.Y.Z 形式的 tag 名字用于指示 module2 版本。

如果 Go 可執(zhí)行程序項目有一個且只有一個可執(zhí)行程序要構(gòu)建,那就比較好辦了,我們可以將上面項目布局進行簡化:

$tree -F -L 1 single-exe-layout
single-exe-layout
├── go.mod
├── internal/
├── main.go
├── pkg1/
├── pkg2/
└── vendor/

你可以看到,我們刪除了 cmd 目錄,將唯一的可執(zhí)行程序的 main 包就放置在項目根目錄下,而其他布局元素的功用不變。

3.2 Go 庫項目的典型結(jié)構(gòu)布局

好了到這里,我們已經(jīng)了解了 Go 可執(zhí)行程序項目的典型布局,現(xiàn)在我們再來看看 Go 庫項目的典型結(jié)構(gòu)布局是怎樣的。

Go 庫項目僅對外暴露 Go 包,這類項目的典型布局形式是這樣的:

$tree -F lib-layout 
lib-layout
├── go.mod
├── internal/
│   ├── pkga/
│   │   └── pkg_a.go
│   └── pkgb/
│       └── pkg_b.go
├── pkg1/
│   └── pkg1.go
└── pkg2/
    └── pkg2.go

我們看到,庫類型項目相比于 Go 可執(zhí)行程序項目的布局要簡單一些。因為這類項目不需要構(gòu)建可執(zhí)行程序,所以去除了 cmd 目錄。

而且,在這里,vendor 也不再是可選目錄了。對于庫類型項目而言,我們并不推薦在項目中放置 vendor 目錄去緩存庫自身的第三方依賴,庫項目僅通過 go.mod 文件明確表述出該項目依賴的 module 或包以及版本要求就可以了。

Go 庫項目的初衷是為了對外部(開源或組織內(nèi)部公開)暴露 API,對于僅限項目內(nèi)部使用而不想暴露到外部的包,可以放在項目頂層的 internal 目錄下面。當然 internal 也可以有多個并存在于項目結(jié)構(gòu)中的任一目錄層級中,關鍵是項目結(jié)構(gòu)設計人員要明確各級 internal 包的應用層次和范圍。

對于有一個且僅有一個包的 Go 庫項目來說,我們也可以將上面的布局做進一步簡化,簡化的布局如下所示:

$tree -L 1 -F single-pkg-lib-layout
single-pkg-lib-layout
├── feature1.go
├── feature2.go
├── go.mod
└── internal/

簡化后,我們將這唯一包的所有源文件放置在項目的頂層目錄下(比如上面的 feature1.go 和 feature2.go),其他布局元素位置和功用不變。

好了,現(xiàn)在我們已經(jīng)了解完目前 Go 項目的典型結(jié)構(gòu)布局了。不過呢,除了這些之外,還要注意一下早期 Go 可執(zhí)行程序項目的經(jīng)典布局,這個又有所不同。

3.3 早期 Go 可執(zhí)行程序項目的典型布局

很多早期接納 Go 語言的開發(fā)者所建立的 Go 可執(zhí)行程序項目,深受 Go 創(chuàng)世項目 1.4 版本之前的布局影響,這些項目將所有可暴露到外面的 Go 包聚合在 pkg 目錄下,就像前面 Go 1.3 版本中的布局那樣,它們的典型布局結(jié)構(gòu)是這樣的:

$tree -L 3 -F early-project-layout
early-project-layout
└── exe-layout/
    ├── cmd/
    │   ├── app1/
    │   └── app2/
    ├── go.mod
    ├── internal/
    │   ├── pkga/
    │   └── pkgb/
    ├── pkg/
    │   ├── pkg1/
    │   └── pkg2/
    └── vendor/

我們看到,原本放在項目頂層目錄下的 pkg1 和 pkg2 公共包被統(tǒng)一聚合到 pkg 目錄下了。而且,這種早期 Go 可執(zhí)行程序項目的典型布局在 Go 社區(qū)內(nèi)部也不乏受眾,很多新建的 Go 項目依然采用這樣的項目布局。

所以,當你看到這樣的布局也不要奇怪,你應該就明確在這樣的布局下 pkg 目錄所起到的“聚類”的作用了。不過,在這里還是建議你在創(chuàng)建新的 Go 項目時,優(yōu)先采用前面的標準項目布局。

四、Go項目典型項目結(jié)構(gòu)分為五部分

放在項目頂層的 Go Module 相關文件,包括 go.mod 和 go.sum;

cmd 目錄:存放項目要編譯構(gòu)建的可執(zhí)行文件所對應的 main 包的源碼文件;

項目包目錄:每個項目下的非 main 包都“平鋪”在項目的根目錄下,每個目錄對應一個 Go 包;

internal 目錄:存放僅項目內(nèi)部引用的 Go 包,這些包無法被項目之外引用;

vendor 目錄:這是一個可選目錄,為了兼容 Go 1.5 引入的 vendor 構(gòu)建模式而存在的。這個目錄下的內(nèi)容均由 Go 命令自動維護,不需要開發(fā)者手工干預。

以上就是深入理解Go中的項目代碼布局的詳細內(nèi)容,更多關于Go項目代碼布局的資料請關注腳本之家其它相關文章!

相關文章

  • Go語言標準錯誤error全面解析

    Go語言標準錯誤error全面解析

    Go語言中的錯誤處理是通過內(nèi)置的error接口來實現(xiàn)的,其中errorString和wrapError是兩種常見的錯誤類型實現(xiàn)方式,errorString通過errors.New()方法實現(xiàn),而wrapError則通過fmt.Errorf()方法實現(xiàn),支持錯誤的嵌套和解析
    2024-10-10
  • Go log庫的使用示例詳解

    Go log庫的使用示例詳解

    Go語言內(nèi)置的log庫提供了基本的日志記錄功能,支持日志的格式化輸出、設置日志前綴、配置輸出位置等,可以通過標準logger或創(chuàng)建新的Logger對象來使用,log庫簡單易用,但功能有限,可能需要配合第三方日志庫如logrus、zap等來滿足復雜需求
    2024-09-09
  • go MethodByName()不能獲取私有方法的解決

    go MethodByName()不能獲取私有方法的解決

    本文主要介紹了go MethodByName()不能獲取私有方法的解決,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-02-02
  • golang使用mapstructure解析json

    golang使用mapstructure解析json

    mapstructure?是一個?Go?庫,用于將通用映射值解碼為結(jié)構(gòu),這篇文章主要來和大家介紹一下golang如何使用mapstructure解析json,需要的可以參考下
    2023-12-12
  • Golang原生rpc(rpc服務端源碼解讀)

    Golang原生rpc(rpc服務端源碼解讀)

    本文主要介紹了Golang原生rpc(rpc服務端源碼解讀),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-04-04
  • Golang單元測試中的技巧分享

    Golang單元測試中的技巧分享

    這篇文章主要為大家詳細介紹了Golang進行單元測試時的一些技巧和科技,文中的示例代碼講解詳細,具有一定的參考價值,感興趣的小伙伴可以了解一下
    2023-03-03
  • Golang?官方依賴注入工具wire示例詳解

    Golang?官方依賴注入工具wire示例詳解

    這篇文章主要為大家介紹了Golang?官方依賴注入工具wire示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-10-10
  • go?doudou應用中使用枚舉類型教程示例

    go?doudou應用中使用枚舉類型教程示例

    這篇文章主要為大家介紹了go?doudou應用中使用枚舉類型教程示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-12-12
  • 詳解Golang官方中的一致性哈希組件

    詳解Golang官方中的一致性哈希組件

    這篇文章主要為大家詳細介紹了Golang官方中的一致性哈希組件的相關知識,文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下
    2023-04-04
  • Go中JSON解析時tag的使用

    Go中JSON解析時tag的使用

    本文主要介紹了Go中JSON解析時tag的使用,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-01-01

最新評論