大多數語言都有「依賴」、「包」等概念,Go語言的依賴處理經歷了幾回變革git
最先的時候,Go所依賴的全部的第三方庫都放在GOPATH這個目錄下面github
從v1.5開始開始引入vendor模式,若是項目目錄下有vendor目錄,那麼go工具鏈會優先使用vendor內的包進行編譯、測試等編程
從v1.11開始,引入了Go Module 做爲依賴解決方案,到v1.14宣佈Go Module已經能夠用於生產環境,到v1.16版本開始Go Module默認開啓json
GOPATH是什麼,輸入以下命令查看網絡
# go env GOPATH GOPATH="/Users/ssgeek/go"
進入到該目錄下,目錄結構以下ide
# cd `go env GOPATH` # tree -L 2 . . ├── bin │ ├── dlv │ ├── go-outline │ ├── gomodifytags │ ├── gopkgs │ ├── goplay │ ├── gopls │ ├── gotests │ ├── impl │ └── staticcheck ├── pkg │ ├── mod │ └── sumdb └── src └── github.com ...
三個目錄中存放的文件說明以下工具
bin //用來存放編譯後的可執行文件 pkg //用於存放編譯後生成的歸檔文件 src //用來存放go源碼文件
在使用GOPATH的模式下,咱們須要將應用代碼存放在固定的$GOPATH/src目錄下,而且若是執行go get來拉取外部依賴會自動下載並安裝到$GOPATH目錄下測試
第三方套件只要不是官方庫,都須要放置在GOPATH/src的路徑下才可使用ui
go get最經常使用在當咱們想用別人公開在GitHub上的套件,能夠幫咱們從網絡clone到GOPATH/src裏面。雖然這樣很方便,可是會發現GOPATH/src下會很複雜,除了有你本身開發的代碼目錄,同時也包含其餘第三方庫的專屬目錄加密
咱們給不一樣的項目設置不一樣的GoPath,優勢很是明顯:
便於管理項目,每一個項目都是不一樣的GoPath,這對於咱們管理多個Golang項目而言,可以很是清晰的處理項目結構。若是咱們把全部項目都放在同一個GoPath的src包下,那麼項目的結構就會變得很是混亂,難以管理
可是當咱們須要依賴第三方的包的時候,不一樣的項目設置不一樣的GoPath的缺點也很是明顯:
爲了解決GOPATH的問題,所以官方在1.11開始推出了Go Modules的功能。Go Modules解決方式很像是Java看到Maven的作法,將第三方庫儲存在本地的空間,而且給項目代碼去引用
總共能夠設置三種不一樣的值
默認值,go命令會根據當前目錄來決定是否啓用modules功能。須要知足兩種情形:
該目錄不在GOPATH/src/下
當前或上一層目錄存在go.mod文件
go命令會使用modules,而不會去GOPATH目錄下查找。
go命令將不會支持module功能,尋找依賴按照之前GOPATH的作法去尋找
目前1.16版本默認將這個參數設置成on,並且可能以後的版本會棄用掉GO111MODULE,所以建議要開發Go項目時就再也不使用GOPATH了,而是採用Go Modules的作法,所以建議都設定爲on
採用Go Modules,下載下來的第三方依賴就位於GOPATH/pkg/mod目錄下
go mod init <module name>
<module name>可填可不填,不填的話預設就是默認的文件名稱go.mod
在此文件中能夠寫如下幾個關鍵字:
定義模組路徑
定義go語言version
指定依賴,預設是最新版,能夠指定版本號
排除該依賴和其版本
使用不一樣的依賴版本並替換原有的依賴版本註解
indirect表明被間接導入的依賴包
假設如今我要引入GitHub上的gin-gonic/gin的依賴,以下定義:
module myProject go 1.16 require github.com/gin-gonic/gin v1.6.3
再執行如下指令:
go mod xxx
會將須要的依賴安裝在GOPATH/pkg/mod目錄裏面
gin@v1.4.0 gin@v1.6.3 gin@v1.7.1
除了go.mod以外,go命令還維護一個名爲go.sum的文件,其中包含特定模塊版本內容的預期加密哈希
go命令使用go.sum文件確保這些模塊的將來下載檢索與第一次下載相同,以確保項目所依賴的模塊不會出現意外更改,不管是出於惡意、意外仍是其餘緣由。 go.mod和go.sum都應檢入版本控制。
go.sum不須要手工維護,因此能夠不用太關注
只要有開啓go modules功能,go get 就不會像之前同樣在GOPATH/src下放置依賴,而是會放在GOPATH/pkg/mod裏面,而且go.mod會寫好引入
經常使用
go mod init:初始化go mod, 生成go.mod文件,後可接參數指定 module 名,上面已經演示過。 go mod download:手動觸發下載依賴包到本地cache(默認爲$GOPATH/pkg/mod目錄) go list -m -json all:以 json 的方式打印依賴詳情
其餘
go mod graph: 打印項目的模塊依賴結構 go mod tidy :添加缺乏的包,且刪除無用的包 go mod verify :校驗模塊是否被篡改過 go mod why: 查看爲何須要依賴 go mod vendor :導出項目全部依賴到vendor下 go mod edit :編輯go.mod文件
GoPath所引出的問題,就是由於第三方類庫的包所致使的,因此在有了GoModule以後,GoPath和GoModule就分別負責不一樣的職責,共同爲Golang項目服務
GoPath用來存放咱們從網上拉取的第三方依賴包
GoModule用來存放咱們本身的Golang項目文件,當本身的項目須要依賴第三方的包的時候,咱們經過GoModule目錄下的一個go.mod文件來引用GoPath目錄pkg包下的mod文件夾下的第三方依賴便可
這樣以來,既解決了原來只能侷限在GoPath目錄src包下進行編程的問題,也解決了第三方依賴包難以管理和重複依賴佔用磁盤空間的問題