新聞中心
最早的時候,Go語言所依賴的所有的第三方庫都放在 GOPATH 這個目錄下面,這就導致了同一個庫只能保存一個版本的代碼。如果不同的項目依賴同一個第三方的庫的不同版本,應該怎么解決?

go module 是Go語言從 1.11 版本之后官方推出的版本管理工具,并且從 Go1.13 版本開始,go module 成為了Go語言默認的依賴管理工具。
Modules 官方定義為:
Modules 是相關 Go 包的集合,是源代碼交換和版本控制的單元。Go語言命令直接支持使用 Modules,包括記錄和解析對其他模塊的依賴性,Modules 替換舊的基于 GOPATH 的方法,來指定使用哪些源文件。
如何使用 Modules?
1) 首先需要把 golang 升級到 1.11 版本以上(現在 1.13 已經發(fā)布了,建議使用 1.13)。
2) 設置 GO111MODULE。
GO111MODULE
在Go語言 1.12 版本之前,要啟用 go module 工具首先要設置環(huán)境變量 GO111MODULE,不過在Go語言 1.13 及以后的版本則不再需要設置環(huán)境變量。通過 GO111MODULE 可以開啟或關閉 go module 工具。
- GO111MODULE=off 禁用 go module,編譯時會從 GOPATH 和 vendor 文件夾中查找包;
- GO111MODULE=on 啟用 go module,編譯時會忽略 GOPATH 和 vendor 文件夾,只根據 go.mod下載依賴;
- GO111MODULE=auto(默認值),當項目在 GOPATH/src 目錄之外,并且項目根目錄有 go.mod 文件時,開啟 go module。
Windows 下開啟 GO111MODULE 的命令為:
set GO111MODULE=on 或者 set GO111MODULE=auto
MacOS 或者 Linux 下開啟 GO111MODULE 的命令為:
export GO111MODULE=on 或者 export GO111MODULE=auto
在開啟 GO111MODULE 之后就可以使用 go module 工具了,也就是說在以后的開發(fā)中就沒有必要在 GOPATH 中創(chuàng)建項目了,并且還能夠很好的管理項目依賴的第三方包信息。
常用的go mod命令如下表所示:
| 命令 | 作用 |
|---|---|
| go mod download | 下載依賴包到本地(默認為 GOPATH/pkg/mod 目錄) |
| go mod edit | 編輯 go.mod 文件 |
| go mod graph | 打印模塊依賴圖 |
| go mod init | 初始化當前文件夾,創(chuàng)建 go.mod 文件 |
| go mod tidy | 增加缺少的包,刪除無用的包 |
| go mod vendor | 將依賴復制到 vendor 目錄下 |
| go mod verify | 校驗依賴 |
| go mod why | 解釋為什么需要依賴 |
GOPROXY
proxy 顧名思義就是代理服務器的意思。大家都知道,國內的網絡有防火墻的存在,這導致有些Go語言的第三方包我們無法直接通過go get命令獲取。GOPROXY 是Go語言官方提供的一種通過中間代理商來為用戶提供包下載服務的方式。要使用 GOPROXY 只需要設置環(huán)境變量 GOPROXY 即可。
目前公開的代理服務器的地址有:
- goproxy.io;
- goproxy.cn:(推薦)由國內的七牛云提供。
Windows 下設置 GOPROXY 的命令為:
go env -w GOPROXY=https://goproxy.cn,direct
MacOS 或 Linux 下設置 GOPROXY 的命令為:
export GOPROXY=https://goproxy.cn
Go語言在 1.13 版本之后 GOPROXY 默認值為 https://proxy.golang.org,在國內可能會存在下載慢或者無法訪問的情況,所以十分建議大家將 GOPROXY 設置為國內的 goproxy.cn。
使用go get命令下載指定版本的依賴包
執(zhí)行go get 命令,在下載依賴包的同時還可以指定依賴包的版本。
- 運行
go get -u命令會將項目中的包升級到最新的次要版本或者修訂版本; - 運行
go get -u=patch命令會將項目中的包升級到最新的修訂版本; - 運行
go get [包名]@[版本號]命令會下載對應包的指定版本或者將對應包升級到指定的版本。
提示:go get [包名]@[版本號]命令中版本號可以是 x.y.z 的形式,例如 go get [email protected],也可以是 git 上的分支或 tag,例如 go get foo@master,還可以是 git 提交時的哈希值,例如 go get foo@e3702bed2。
如何在項目中使用
【示例 1】創(chuàng)建一個新項目:
1) 在 GOPATH 目錄之外新建一個目錄,并使用go mod init初始化生成 go.mod 文件。
go mod init hello
go: creating new go.mod: module hello
go.mod 文件一旦創(chuàng)建后,它的內容將會被 go toolchain 全面掌控,go toolchain 會在各類命令執(zhí)行時,比如go get、go build、go mod等修改和維護 go.mod 文件。
go.mod 提供了 module、require、replace 和 exclude 四個命令:
- module 語句指定包的名字(路徑);
- require 語句指定的依賴項模塊;
- replace 語句可以替換依賴項模塊;
- exclude 語句可以忽略依賴項模塊。
初始化生成的 go.mod 文件如下所示:
module hello
go 1.13
2) 添加依賴。
新建一個 main.go 文件,寫入以下代碼:
package main
import (
"net/http"
"github.com/labstack/echo"
)
func main() {
e := echo.New()
e.GET("/", func(c echo.Context) error {
return c.String(http.StatusOK, "Hello, World!")
})
e.Logger.Fatal(e.Start(":1323"))
} 執(zhí)行go run main.go運行代碼會發(fā)現 go mod 會自動查找依賴自動下載:
go run main.go
go: finding github.com/labstack/echo v3.3.10+incompatible
go: downloading github.com/labstack/echo v3.3.10+incompatible
go: extracting github.com/labstack/echo v3.3.10+incompatible
go: finding github.com/labstack/gommon v0.3.0
......
go: finding golang.org/x/text v0.3.0
____ __
/ __/___/ / ___
/ _// __/ _ \/ _ \
/___/\__/_//_/\___/ v3.3.10-dev
High performance, minimalist Go web framework
https://echo.labstack.com
____________________________________O/_______
O\
? http server started on [::]:1323
現在查看 go.mod 內容:
module hello
go 1.13
require (
github.com/labstack/echo v3.3.10+incompatible // indirect
github.com/labstack/gommon v0.3.0 // indirect
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 // indirect
)
go module 安裝 package 的原則是先拉取最新的 release tag,若無 tag 則拉取最新的 commit,詳見 Modules 官方介紹。
go 會自動生成一個 go.sum 文件來記錄 dependency tree:
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/labstack/echo v3.3.10+incompatible h1:pGRcYk231ExFAyoAjAfD85kQzRJCRI8bbnE7CX5OEgg=
github.com/labstack/echo v3.3.10+incompatible/go.mod h1:0INS7j/VjnFxD4E2wkz67b8cVwCLbBmJyDaka6Cmk1s=
github.com/labstack/gommon v0.3.0 h1:JEeO0bvc78PKdyHxloTKiF8BD5iGrH8T6MSeGvSgob0=
github.com/labstack/gommon v0.3.0/go.mod h1:MULnywXg0yavhxWKc+lOruYdAhDwPK9wf0OL7NoOu+k=
github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
... 省略很多行
再次執(zhí)行腳本go run main.go發(fā)現跳過了檢查并安裝依賴的步驟。
可以使用命令go list -m -u all來檢查可以升級的 package,使用go get -u need-upgrade-package升級后會將新的依賴版本更新到 go.mod * 也可以使用go get -u升級所有依賴。
【示例 2】改造現有項目。
項目目錄結構為:
├─ main.go
│
└─ api
└─ apis.go
main.go 源碼為:
package main
import (
api "./api" // 這里使用的是相對路徑
"github.com/labstack/echo"
)
func main() {
e := echo.New()
e.GET("/", api.HelloWorld)
e.Logger.Fatal(e.Start(":1323"))
} api/apis.go 源碼為:
package api
import (
"net/http"
"github.com/labstack/echo"
)
func HelloWorld(c echo.Context) error {
return c.JSON(http.StatusOK, "hello world")
} 1) 使用 go mod init *** 初始化 go.mod。
go mod init hello
go: creating new go.mod: module hello
2) 運行go run main.go。
go run main.go
go: finding golang.org/x/crypto latest
build _/D_/code/src/api: cannot find module for path _/D_/code/src/api
首先還是會查找并下載安裝依賴,然后運行腳本 main.go,這里會拋出一個錯誤:
build _/D_/code/src/api: cannot find module for path _/D_/code/src/api
但是 go.mod 已經更新:
module hello
go 1.13
require (
github.com/labstack/echo v3.3.10+incompatible // indirect
github.com/labstack/gommon v0.3.0 // indirect
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413 // indirect
)
那為什么會拋出這個錯誤呢?
這是因為 main.go 中使用 internal package 的方法跟以前已經不同了,由于 go.mod 會掃描同工作目錄下所有 package 并且變更引入方法,必須將 hello 當成路徑的前綴,也就是需要寫成 import hello/api,以往 GOPATH/dep 模式允許的 import ./api 已經失效。
3) 更新舊的 package import 方式。
所以 main.go 需要改寫成:
package main
import (
api "hello/api" // 這里使用的是相對路徑
"github.com/labstack/echo"
)
func main() {
e := echo.New()
e.GET("/", api.HelloWorld)
e.Logger.Fatal(e.Start(":1323"))
}提示:在 Go語言 1.11 版本下使用 go mod 時可能會遇到 go build github.com/valyala/fasttemplate: module requires go 1.12 這種錯誤,遇到類似這種需要升級到 1.12 的問題,直接升級到Go語言1.12 版本以上就好了。
4) 到這里就和新創(chuàng)建一個項目沒什么區(qū)別了。
使用 replace 替換無法直接獲取的 package
由于某些已知的原因,并不是所有的 package 都能成功下載,比如:golang.org 下的包。
modules 可以通過在 go.mod 文件中使用 replace 指令替換成 github 上對應的庫,比如:
replace (
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a => github.com/golang/crypto v0.0.0-20190313024323-a1f597ede03a
)
或者
replace golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a => github.com/golang/crypto v0.0.0-20190313024323-a1f597ede03a
網頁題目:創(chuàng)新互聯GO教程:Go語言gomod包依賴管理工具使用詳解
轉載注明:http://m.fisionsoft.com.cn/article/cossphp.html


咨詢
建站咨詢
