1、概述
大多數語言都有“依賴”、“包”等概念,Go
語言的依賴處理經歷了幾次變革
最早的時候,Go
所依賴的所有的第三方庫都放在GOPATH
這個目錄下面
從v1.5
開始開始引入vendor
模式,如果項目目錄下有vendor
目錄,那么go
工具鏈會優先使用vendor
內的包進行編譯、測試等
從v1.11
開始,引入了Go Module
作為依賴解決方案,到v1.14
宣布Go Module
已經可以用於生產環境,到v1.16
版本開始Go Module
默認開啟
2、GOPATH介紹
2.1 GOPATH目錄
GOPATH
是什么,輸入如下命令查看
# go env GOPATH
GOPATH="/Users/ssgeek/go"
進入到該目錄下,目錄結構如下
# 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源碼文件
2.2 GOPATH的缺點
在使用GOPATH
的模式下,我們需要將應用代碼存放在固定的$GOPATH/src
目錄下,並且如果執行go get
來拉取外部依賴會自動下載並安裝到$GOPATH
目錄下
第三方套件只要不是官方庫,都需要放置在GOPATH/src
的路徑下才可以使用
go get
最常用在當我們想用別人公開在GitHub
上的套件,可以幫我們從網絡clone
到GOPATH/src
里面。雖然這樣很方便,但是會發現GOPATH/src
下會很復雜,除了有你自己開發的代碼目錄,同時也包含其他第三方庫的專屬目錄
我們給不同的項目設置不同的GoPath
,優點非常明顯:
便於管理項目,每個項目都是不同的GoPath
,這對於我們管理多個Golang
項目而言,能夠非常清晰的處理項目結構。如果我們把所有項目都放在同一個GoPath
的src
包下,那么項目的結構就會變得非常混亂,難以管理
但是當我們需要依賴第三方的包的時候,不同的項目設置不同的GoPath
的缺點也非常明顯:
- 第三方依賴的包和我們自己的
Golang
包混在一起,會給我們的項目文件管理帶來一定的麻煩 - 不同的
GoPath
都需要下載依賴,那么磁盤中重復的依賴就會非常多,會占用我們大量的磁盤空間
3、GO Module介紹
為了解決GOPATH
的問題,因此官方在1.11
開始推出了Go Modules
的功能。Go Modules
解決方式很像是Java
看到Maven
的做法,將第三方庫儲存在本地的空間,並且給項目代碼去引用
3.1 設定GO111MODULE環境變量
總共可以設置三種不同的值
- auto
默認值,go
命令會根據當前目錄來決定是否啟用modules
功能。需要滿足兩種情形:
該目錄不在GOPATH/src/
下
當前或上一層目錄存在go.mod
文件
- on
go
命令會使用modules
,而不會去GOPATH
目錄下查找。
- off
go
命令將不會支持module
功能,尋找依賴按照以前GOPATH
的做法去尋找
目前1.16
版本默認將這個參數設置成on
,而且可能之后的版本會棄用掉GO111MODULE
,因此建議要開發Go
項目時就不再使用GOPATH
了,而是采用Go Modules
的做法,因此建議都設定為on
采用Go Modules
,下載下來的第三方依賴就位於GOPATH/pkg/mod
目錄下
3.2 初始化mod
go mod init <module name>
<module name>
可填可不填,不填的話預設就是默認的文件名稱go.mod
在此文件中可以寫以下幾個關鍵字:
- module
定義模組路徑
- go
定義go
語言version
- require
指定依賴,預設是最新版,可以指定版本號
- exclude
排除該依賴和其版本
- replace
使用不同的依賴版本並替換原有的依賴版本注解
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
會寫好引入
3.3 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文件
4、總結
GoPath
所引出的問題,就是因為第三方類庫的包所導致的,所以在有了GoModule
之后,GoPath
和GoModule
就分別負責不同的職責,共同為Golang
項目服務
GoPath
用來存放我們從網上拉取的第三方依賴包
GoModule
用來存放我們自己的Golang
項目文件,當自己的項目需要依賴第三方的包的時候,我們通過GoModule
目錄下的一個go.mod
文件來引用GoPath
目錄pkg
包下的mod
文件夾下的第三方依賴即可
這樣以來,既解決了原來只能局限在GoPath
目錄src
包下進行編程的問題,也解決了第三方依賴包難以管理和重復依賴占用磁盤空間的問題