什么是go.mod?
Go.mod是Golang1.11版本新引入的官方包管理工具用於解決之前沒有地方記錄依賴包具體版本的問題,方便依賴包的管理。
Go.mod其實就是一個Modules,關於Modules的官方定義為:
Modules是相關Go包的集合,是源代碼交換和版本控制的單元。go命令直接支持使用Modules,包括記錄和解析對其他模塊的依賴性。Modules替換舊的基於GOPATH的方法,來指定使用哪些源文件。
Modules和傳統的GOPATH不同,不需要包含例如src,bin這樣的子目錄,一個源代碼目錄甚至是空目錄都可以作為Modules,只要其中包含有go.mod文件。
如何使用go.mod?
1.首先將go的版本升級為1.11以上
2.設置GO111MODULE
GO111MODULE
GO111MODULE
有三個值:off
, on
和auto(默認值)
。
GO111MODULE=off
,go命令行將不會支持module功能,尋找依賴包的方式將會沿用舊版本那種通過vendor目錄或者GOPATH模式來查找。GO111MODULE=on
,go命令行會使用modules,而一點也不會去GOPATH目錄下查找。GO111MODULE=auto
,默認值,go命令行將會根據當前目錄來決定是否啟用module功能。這種情況下可以分為兩種情形:- 當前目錄在GOPATH/src之外且該目錄包含go.mod文件
- 當前文件在包含go.mod文件的目錄下面。
go mod命令:
golang 提供了 go mod
命令來管理包。go mod 有以下命令:
go.mod如何在項目中使用?
1.首先我們要在GOPATH/src 目錄之外新建工程,或將老工程copy到GOPATH/src 目錄之外。
PS:go.mod文件一旦創建后,它的內容將會被go toolchain全面掌控。go toolchain會在各類命令執行時,比如go get、go build、go mod等修改和維護go.mod文件。
go.mod 提供了module
, require
、replace
和exclude
四個命令
module
語句指定包的名字(路徑)require
語句指定的依賴項模塊replace
語句可以替換依賴項模塊exclude
語句可以忽略依賴項模塊
下面是我們建立了一個hello.go的文
package main import ( "fmt" ) func main() { fmt.Println("Hello, world!") }
2.在當前目錄下,命令行運行 go mod init + 模塊名稱 初始化模塊
即go mod init hello
運行完之后,會在當前目錄下生成一個go.mod文件,這是一個關鍵文件,之后的包的管理都是通過這個文件管理。
官方說明:除了go.mod之外,go命令還維護一個名為go.sum的文件,其中包含特定模塊版本內容的預期加密哈希
go命令使用go.sum文件確保這些模塊的未來下載檢索與第一次下載相同的位,以確保項目所依賴的模塊不會出現意外更改,無論是出於惡意、意外還是其他原因。 go.mod和go.sum都應檢入版本控制。
go.sum 不需要手工維護,所以可以不用太關注。
注意:子目錄里是不需要init的,所有的子目錄里的依賴都會組織在根目錄的go.mod文件里
接下來,讓我們的項目依稀一下第三方包
如修改hello.go文件如下,按照過去的做法,要運行hello.go需要執行go get
命令 下載gorose包到 $GOPATH/src
package main import ( "fmt" "github.com/gohouse/gorose" ) func main() { fmt.Println("Hello, world!") }
但是,使用了新的包管理就不在需要這樣做了
直接 go run hello.go
稍等片刻… go 會自動查找代碼中的包,下載依賴包,並且把具體的依賴關系和版本寫入到go.mod和go.sum文件中。
查看go.mod,它會變成這樣:
module test require ( github.com/gohouse/gorose v1.0.5 )
require
關鍵字是引用,后面是包,最后v1.11.1 是引用的版本號
這樣,一個使用Go包管理方式創建項目的小例子就完成了。
問題一:依賴的包下載到哪里了?還在GOPATH里嗎?
不在。
使用Go的包管理方式,依賴的第三方包被下載到了$GOPATH/pkg/mod
路徑下。
問題二: 依賴包的版本是怎么控制的?
在上一個問題里,可以看到最終下載在$GOPATH/pkg/mod
下的包中最后會有一個版本號 v1.0.5,也就是說,$GOPATH/pkg/mod
里可以保存相同包的不同版本。
版本是在go.mod中指定的。如果,在go.mod中沒有指定,go命令會自動下載代碼中的依賴的最新版本,本例就是自動下載最新的版本。如果,在go.mod用require語句指定包和版本 ,go命令會根據指定的路徑和版本下載包,
指定版本時可以用latest
,這樣它會自動下載指定包的最新版本;
問題三: 可以把項目放在$GOPATH/src下嗎?
可以。但是go會根據GO111MODULE的值而采取不同的處理方式,默認情況下,GO111MODULE=auto
自動模式
1.auto 自動模式下,項目在$GOPATH/src
里會使用$GOPATH/src
的依賴包,在$GOPATH/src外,就使用go.mod 里 require的包
2.on 開啟模式,1.12后,無論在$GOPATH/src
里還是在外面,都會使用go.mod 里 require的包
3.off 關閉模式,就是老規矩。
問題三: 依賴包中的地址失效了怎么辦?比如 golang.org/x/… 下的包都無法下載怎么辦?
在go快速發展的過程中,有一些依賴包地址變更了。以前的做法:
1.修改源碼,用新路徑替換import的地址
2.git clone 或 go get 新包后,copy到$GOPATH/src里舊的路徑下
無論什么方法,都不便於維護,特別是多人協同開發時。
使用go.mod就簡單了,在go.mod文件里用 replace 替換包,例如
replace golang.org/x/text => github.com/golang/text latest
這樣,go會用 github.com/golang/text 替代golang.org/x/text,原理就是下載github.com/golang/text 的最新版本到 $GOPATH/pkg/mod/golang.org/x/text
下。
問題四: init生成的go.mod的模塊名稱有什么用?
本例里,用 go mod init hello 生成的go.mod文件里的第一行會申明module hello
因為我們的項目已經不在$GOPATH/src
里了,那么引用自己怎么辦?就用模塊名+路徑。
例如,在項目下新建目錄 utils,創建一個tools.go文件:
-
package utils import "fmt" func PrintText(text string) { fmt.Println(text) }
在根目錄下的hello.go文件就可以 import “hello/utils” 引用utils
-
package main import ( "hello/utils" "github.com/astaxie/beego" ) func main() { utils.PrintText("Hi") beego.Run() }
問題五:以前老項目如何用新的包管理
- 如果用auto模式,把項目移動到
$GOPATH/src
外 - 進入目錄,運行
go mod init + 模塊名稱
go build
或者go run
一次
原文地址 https://blog.csdn.net/weixin_39003229/article/details/97638573