Golang modules 初探
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
今天天色剛剛亮起,起床看到golang 1.11正式發(fā)版了,有著兩個(gè)重要的特性:modules和WebAssembly。
本博文只要說的是modules,從Java轉(zhuǎn)golang的同學(xué)肯定是對(duì)golang的包管理充滿了無奈之情,我也曾在博客中介紹過glide,也介紹過dep,現(xiàn)在我們?cè)僖淮紊?jí)介紹modules。
什么是modules
現(xiàn)在都在說modules,那么它是什么?
到文檔看看 Modules, module versions, and more:
翻譯一下:
模塊是相關(guān)Go包的集合。modules是源代碼交換和版本控制的單元。 go命令直接支持使用modules,包括記錄和解析對(duì)其他模塊的依賴性。modules替換舊的基于GOPATH的方法來指定在給定構(gòu)建中使用哪些源文件。可以得到兩個(gè)重要信息:
- Go命令行支持modules操作
- modules用來替換GOPATH的
大家不需要太擔(dān)心了,golang 1.11版本僅僅是指對(duì)modules的初步支持,之前老的GOPATH還是可以繼續(xù)使用的,有人說是在golang 1.12去除,但是我覺得有點(diǎn)早了,畢竟人的慣性不是這么容易改變的。
如何使用modules
modules是一個(gè)新的特性,那么就需要新的Golang版本進(jìn)行支持了,可以到官網(wǎng)下載,一定要是go 1.11及以上的版本(寫博文的時(shí)候go 1.11剛剛出來)。 怎么部署就不在這里說了,相信初學(xué)者也是知道怎么做的。
還有人記得vendor剛剛出來時(shí)候golang提供的環(huán)境變量GO15VENDOREXPERIMENT嗎?現(xiàn)在modules出來,按照慣例也提供了一個(gè)環(huán)境變量GO111MODULE,這個(gè)變量的三個(gè)1太有魔性了。
GO111MODULE
GO111MODULE可以設(shè)置為三個(gè)字符串值之一:off,on或auto(默認(rèn)值)。
- off,則go命令從不使用新模塊支持。它查找vendor 目錄和GOPATH以查找依賴關(guān)系;也就是繼續(xù)使用“GOPATH模式”。
- on,則go命令需要使用模塊,go 會(huì)忽略 GOPATH 和 vendor 文件夾,只根據(jù) go.mod下載依賴。
- auto或未設(shè)置,則go命令根據(jù)當(dāng)前目錄啟用或禁用模塊支持。僅當(dāng)當(dāng)前目錄位于GOPATH/src之外并且其本身包含go.mod文件或位于包含go.mod文件的目錄下時(shí),才啟用模塊支持。
Defining a module
開始的時(shí)候誰也不知道怎么使用?不過go已經(jīng)給我提供了工具了,可以在控制臺(tái)輸入:
go help modules看到一大串的文檔輸出,看著都頭疼了,一會(huì)兒我們?cè)俸?jiǎn)要說明重點(diǎn),現(xiàn)在先進(jìn)行操作。
qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ export GO111MODULE=on #開啟modulesqiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ go mod init gitlab.luojilab.com/zeroteam/ddkafka # 創(chuàng)建go.mod go: creating new go.mod: module gitlab.luojilab.com/zeroteam/ddkafkaqiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ ls # 真的創(chuàng)建了,google大法好呀 README.md go.mod models.go mq_interface.go sarama segmentio qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ cat go.mod # 看看里面什么東西 module gitlab.luojilab.com/zeroteam/ddkafka qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ cd segmentio/ qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module) $ go test # 執(zhí)行一下看看 go: finding github.com/segmentio/kafka-go latest go: finding github.com/golang/glog latest go: downloading github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b go: downloading github.com/segmentio/kafka-go v0.0.0-20180716203113-48c37f796910 qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module) $ go list -m gitlab.luojilab.com/zeroteam/ddkafka細(xì)心的同學(xué)一定可以發(fā)現(xiàn),執(zhí)行g(shù)o mod init [module]使用go.mod只有一行信息module gitlab.luojilab.com/zeroteam/ddkafka,在執(zhí)行 go build、 go test、 go list命令時(shí)會(huì)根據(jù)需要的依賴自動(dòng)生成 require語句。
現(xiàn)在來說說如何定義一個(gè)modules,modules是由Go源文件目錄結(jié)構(gòu)定義的,如果目錄下含有g(shù)o.mod文件,該目錄稱為模塊根目錄(module root)。模塊根目錄及其子目錄所有的Go包都是屬于該modules的,但是如果子目錄包含有了自己的go.mod文件就隸屬于該modules。 舉一個(gè)例子:
qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka (module) $ tree . |-- README.md |-- go.mod |-- go.sum |-- models.go |-- mq_interface.go |-- sarama | |-- sarama_consumer.go | |-- sarama_consumer_test.go | |-- sarama_producer.go | `-- sarama_producter_test.go `-- segmentio|-- segmention_Consumer.go|-- segmention_consumer_test.go|-- segmention_producer.go`-- segmention_producter_test.gogitlab.luojilab.com/zeroteam/ddkafka目錄下含有了go.mod文件,所以其子目錄sarama和segmentio都屬于gitlab.luojilab.com/zeroteam/ddkafka模塊,但是如果在segmentio目錄中加入了go.mod,那么segmentio就不再隸屬于gitlab.luojilab.com/zeroteam/ddkafka模塊。
那么依賴被下載到哪里了呢,你可以打開的目錄$GPATH/pkg/mod就可以看到了。
主模塊和構(gòu)建列表
The main module and the build list 暫且翻譯為主模塊和構(gòu)建列表。 “主模塊”是包含運(yùn)行g(shù)o命令的目錄的模塊。 go命令通過查找當(dāng)前目錄中的go.mod或者當(dāng)前目錄的父目錄,或者祖父目錄,依次遞歸查找。
go.mod文件可以通過require,replace和exclude語句使用的精確軟件包集。
- require語句指定的依賴項(xiàng)模塊
- replace語句可以替換依賴項(xiàng)模塊
- exclude語句可以忽略依賴項(xiàng)模塊
go list,可以查看當(dāng)前的依賴和版本.
qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module) $ ls # 這是模塊的子目錄 segmention_Consumer.go segmention_consumer_test.go segmention_producer.go segmention_producter_test.goqiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module) $ go list -m #主模塊的打印路徑 gitlab.luojilab.com/zeroteam/ddkafka qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module) $ go list -m -f={{.Dir}} #print主模塊的根目錄 D:\code\gopath\src\gitlab.luojilab.com\zeroteam\ddkafka qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/segmentio (module) $ go list -m all # 查看當(dāng)前的依賴和版本信息 gitlab.luojilab.com/zeroteam/ddkafka github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b github.com/segmentio/kafka-go v0.0.0-20180716203113-48c37f796910go mod 命令
go mod命令之前可以使用過了go mod init,下面我們把常用的go mod命令羅列一下:
- go mod init:初始化modules
- go mod download:下載modules到本地cache
- go mod edit:編輯go.mod文件,選項(xiàng)有-json、-require和-exclude,可以使用幫助go help mod edit
- go mod graph:以文本模式打印模塊需求圖
- go mod tidy:刪除錯(cuò)誤或者不使用的modules
- go mod vendor:生成vendor目錄
- go mod verify:驗(yàn)證依賴是否正確
- go mod why:查找依賴
go的 mod與get
go get這個(gè)命令大家應(yīng)該不會(huì)陌生,這是下載go依賴包的根據(jù),下載Go 1.11出來了,go get命令也與時(shí)俱進(jìn),支持了modules。 go get 來更新 module:
- 運(yùn)行 go get -u 將會(huì)升級(jí)到最新的次要版本或者修訂版本
- 運(yùn)行 go get -u=patch 將會(huì)升級(jí)到最新的修訂版本(比如說,將會(huì)升級(jí)到 1.0.1 版本,但不會(huì)升級(jí)到 1.1.0 版本)
- 運(yùn)行 go get package@version將會(huì)升級(jí)到指定的版本號(hào)
運(yùn)行g(shù)o get如果有版本的更改,那么go.mod文件也會(huì)更改。
如何處理被墻
我原本以為go 1.11版本modules不支持代理功能,但是經(jīng)過驗(yàn)證,是支持的。使用的命令就是之前提到過的replace命令。 文檔中有一段話:
The -replace=old[@v]=new[@v] and -dropreplace=old[@v] flags add and drop a replacement of the given module path and version pair. If the @v in old@v is omitted, the replacement applies to all versions with the old module path. If the @v in new@v is omitted, the new path should be a local module root directory, not a module path. Note that -replace overrides any existing replacements for old[@v].大概翻譯一下:
-replace=old[@v]=new[@v]和-dropreplace=old[@v]標(biāo)志添加和刪除給定模塊路徑和版本對(duì)的替換。 如果省略了old@v中的@v,則替換適用于所有使用舊模塊路徑的版本。 如果new@v中的@v被省略,新路徑應(yīng)該是本地模塊根目錄,而不是模塊路徑。注意-replace會(huì)覆蓋任何現(xiàn)有的舊替換[@v]。下面進(jìn)行演示: 新建一個(gè)main文件代碼如下:
package mainimport ("errors""fmt""golang.org/x/net/netutil""net""time" )var errFake = errors.New("fake error from errorListener")type errorListener struct {net.Listener }func main() {donec := make(chan bool, 1)go func() {const n = 2ll := netutil.LimitListener(errorListener{}, n)for i := 0; i < n+1; i++ {_, err := ll.Accept()if err != errFake {fmt.Errorf("Accept error = %v; want errFake", err)}}donec <- true}()select {case <-donec:case <-time.After(5 * time.Second):fmt.Errorf("timeout. deadlock?")} }可以看到我們引入了golang.org/x/net/netuti,很不幸,這是不能訪問到的類庫(kù)。
qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module) $ go build # 試試是否可以下載 build gitlab.luojilab.com/zeroteam/ddkafka/cmd: cannot find module for path golang.org/x/net/netutilqiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module) $ go mod edit -require=golang.org/x/net@v1.2.3 # modules中加上依賴,版本是亂給的qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module) $ go build # 還是不行 go: golang.org/x/net@v1.2.3: unrecognized import path "golang.org/x/net" (https fetch: Get https://golang.org/x/net?go-get=1: dial tcp 216.239.37.1:443: connectex: A connection attemp t failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.) go: error loading module requirements以失敗而告終!不過我們還有replace方法,首先去下載
qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/github.com/golang $ git clone https://github.com/golang/net.git Cloning into 'net'... remote: Counting objects: 7876, done. remote: Compressing objects: 100% (55/55), done. remote: Total 7876 (delta 37), reused 42 (delta 19), pack-reused 7802R Receiving objects: 100% (7876/7876), 6.35 MiB | 812.00 KiB/s, done. Resolving deltas: 100% (5443/5443), done.qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/github.com/golang/net (master) $ go mod init github.com/golang/net #創(chuàng)建modules go: creating new go.mod: module github.com/golang/netqiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/github.com/golang/net (master) $ cat go.mod module github.com/golang/net回到原來的項(xiàng)目:
qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module) $ go mod edit -require=golang.org/x/net@v1.2.3 # qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module) $ go mod edit -replace=golang.org/x/net@v1.2.3=/d/code/gopath/src/github.com/golang/net # 使用replace替換到指定的目錄了qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module) $ go build # 這一次成功了qiang@DESKTOP-2A835P9 MINGW64 /d/code/gopath/src/gitlab.luojilab.com/zeroteam/ddkafka/cmd (module) $ ls cmd.exe main.go最后
最后說明一下最新出來的特性不建議立即使用到線上,最好再等等,等迭代一兩個(gè)版本之后,得帶最佳實(shí)踐出來之后,畢竟現(xiàn)在支持modules模式的類庫(kù)還真不多。
附錄
- https://tip.golang.org/cmd/go/#hdr-Modules__module_versions__and_more
- https://roberto.selbach.ca/intro-to-go-modules
轉(zhuǎn)載于:https://my.oschina.net/qiangmzsx/blog/1934149
總結(jié)
以上是生活随笔為你收集整理的Golang modules 初探的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: LNMP架构搭建
- 下一篇: 大数据营销的7个雷区,千万别中招