golang go 包管理工具 go mod的詳細介紹 --- 趕緊擁抱 go mod吧,go path的那套東西已經out了。
go mod go官方的module管理工具
原文:https://github.com/googege/blog
用法:
在一個非go path的路徑中新建一個專案,然後使用go mod init
就可以初始化一個新的包(要開啟這個export GO111MODULE=on
寫入.bash_profile即可 win的同學自己找找設定 GO111MODULE的win版本設定方法哈),其實跟github(gitlab都行)用在一起更好
- 在github上新建一個專案,例如說 test
- 在本地將這個遠端包給clone過來,然後這個資料夾裡面就是一個.git 隱藏的檔案專案這個就是git的管理檔案包
-
將此包放在遠離 go path的檔案路徑裡,然後使用
go mod init
就可以建立一個名為 github.com/XXX/test的包
記住,這個包名不能隨意稱呼,你的資料夾的名稱就是你的包名然後裡面的XX.go的名字無所謂,只要package test
用對就可以了,然後你會發現你的包內出現了兩個檔案go.sum 和go.mod 這個sum包你可以忽略,主要是go.mod包這裡的包 首先開頭是 module github.com/XXX/test 聲明瞭 這個包的具體名稱是"github.com/XXX/test" 但是在呼叫的時候 包的名稱是 test為什麼module後面要加上所有的路徑呢,原因也是很簡單,就是當你go get github.com/xxx/test
的時候用,不然你只有一個test go get是沒辦法下載這個包的。 - 將這個包釋出到github即可。
版本
-
你本地的專案引用別人的包的時候可以在go.mod 中指定version的版本,但是什麼都不指定也可以,預設是latest,也就是你直接
go get github.com/xx/app
的時候它自動就是引入latest的版本了,要指定某個版本你在go.mod 改了就行了。但是記得你的更改不會改變第三個人用你的包時候然後預設下載你的包引用的包的版本,indirect的包(非直接引用的包)的版本是自己定的,不跟引用的直接的包有關係。(能明白吧我感覺有點繞,:stuck_out_tongue_closed_eyes:)
require github.com/coastroad/test v0.0.0-20190216094021-0555a706efff // indirect
這裡 後面就是指定的版本 // indirect就是間接引用的意思。
-
你的包的具體version其實是 git來管理的 1 你可以使用 git push -tag 來指定某一個version.
第二你可以選擇不寫version
然後別人用你的包的時候就不能指定這個version了只能用 latest來引入包 通常來說是你最後編輯的日期例如
v0.0.0-20190216094-55a706efff
-
版本 version2.X version 3.X該怎麼辦?go mod官方推薦的方法如下
module github.com/xxx/test/v2
也就是說你的包的名字還是test但是因為版本是v2.X 所以要在包名後面加入大版本號 /v2(一定是v+數字 比如 v2 v3 v4 v5不能改變寫法也不能用v2.3這種寫法)
然後 呼叫的時候是這樣的
package dd import( "github.com/xxx/test/v2" ) func dd(){ test.Test() }
也就是說使用imprt的時候 也要加 v2大版本號,但是在函式內呼叫的時候 還是test 比如這個時候你的版本是v2.45
那麼 你的mod檔案裡最後的標註就是v2.45
就算不是v2.45不通過打tag的方式來發布 比如還是預設的數字,那麼只要你在mod中指定是v2 你的版本大號就是v2
在import中引入還是需要加上v2 只是在mod中 顯示的資訊是你的最後編輯時間。
還有種寫法是
module github.com/xx/app.v2
這種寫法也是類似,只是官方不推薦這種寫法。
綜上:
// 你的包 go.mod 檔案寫法 : module github.com/xxx/test/v2 別人用你的包的寫法 import( "github.com/xxx/test/v2" ) func dd(){ test.Test() }
包的存放位置
再使用了go mod後你的go path將沒有用了,但是存放的包的位置還是在 老的go path 更明確來說是在 $gopath/src路徑
這個路徑會有兩個檔案 pkg bin 前面這個包是存放的非可執行的包 後面的bin放置的就是可執行的包,你可以把path指向這個bin即可。
go mod tidy
這個命令很有用 首先我們看看它的官方解釋tidy: add missing and remove unused modules
也就是說 你的go.mod中多引入的或者是少引入的 使用go mod tidy
它可以幫你處理
我的包是可執行的檔案,我釋出到github上讓人使用我的mod該怎麼辦
你的go.mod 可以寫成github.com/xxx/test
但是你的檔案的package 應該寫成main 或者目前而言在github上的
可執行檔案的包沒有go.mod也可以,你只需要在本地開發的時候有go.mod即可。然後這個go.mod 中的名稱不跟package一樣也可以
因為別人是不會再引用你的包的了。但是如果你的包有子包,那麼你還是應該把你的包go.mod檔案裡的 module 後面規規矩矩的寫例如
module github.com/XXX/add 然後別人引用的時候 import( "gitub.com/xxx/ddd/app" // app 是子包 即可。 )
我無法使用goalng.org/x的包我該怎麼辦
例如:
你本地的包要引入 golang.org/x/net/html
但是被封了,那麼你可以使用github上的映象包 例如說是 github.com/golang/x/net/html
在你的專案的go.mod 中 加入 replace golang.org/x/net/html => github.com/golang/x/net/html
但是一般你科學上網不就行了嗎。。
我該怎麼處理我的子包和我的包的關係
-
本地
在本地 比如說你的大包要引用子包的內容你可以go.mod 中使用replace,比如github.com/app/中
要引入 github.com/app/app的東西,你可以 在go.mod 中 用 replace github.com/app/app => ./app 即可
當,你釋出的時候你把這個replace刪掉即可。(僅限 *Unix系統,就是改變路徑而已,win的同學自己看看咋弄就ok了,反正釋出的時候要刪除)
當我的資料夾的名稱跟我的package寫的包名不一樣怎麼辦
要記得 一個資料夾(包)內的package 名稱必須相同,但是可以不跟資料夾的名稱一樣,使用的時候其實很不爽就是了
不過也可以用 用法是
比如一個包 它的資料夾是 app 但是 package中的名稱是 app1 那麼可以這麼用
imoirt "github.com/xxx/app" //這個地方要跟資料夾的名稱保持一致 其實就是跟路徑保持一致 func dd(){ app1.xxx// 這裡要跟真實的package保持一致 你看 得不償失吧 所以 資料夾的名稱要跟package的名稱保持一致 }
注意
你的包如果存放在github上 你的包的go.mod module後面一定是github.com/xxx/xxx不能直接寫成 xxx 這樣的話
go mod 無法獲得包 錯誤是parsing go.mod: unexpected module path "test" go: error loading module requirements
總結:
-
也就是說 go.mod 的module 要跟go get xx/xxx 保持一致 例:
module github.com/app/app
在使用開啟 go mod後 使用go get 的時候也是
go get github.com/app/app
-
資料夾可以不跟package的具體包名保持一致,import的時候是用的資料夾名(路徑), 函式中時候是用的package的名字
-
有main包的時候 go.mod 要跟資料夾的名稱保持一致,子包該怎麼引入就怎麼引入 例如 github.com/app/dd
dd是子包 app這個路徑中是main包。
:warning:
go help mod
The commands are: downloaddownload modules to local cache editedit go.mod from tools or scripts graphprint module requirement graph initinitialize new module in current directory tidyadd missing and remove unused modules vendormake vendored copy of dependencies verifyverify dependencies have expected content whyexplain why packages or modules are needed