<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Go語(yǔ)言重新開(kāi)始,Go Modules 的前世今生與基本使用

          共 6684字,需瀏覽 14分鐘

           ·

          2021-12-18 13:37

          2020 年騰訊內(nèi)部的一份開(kāi)發(fā)者報(bào)告顯示,Go 語(yǔ)言已經(jīng)成為騰訊內(nèi)部第二大后端開(kāi)發(fā)語(yǔ)言,在騰訊每天有大量的 Go 開(kāi)發(fā)者在做業(yè)務(wù)和平臺(tái)開(kāi)發(fā),大量的團(tuán)隊(duì)和項(xiàng)目使用也暴露出一些問(wèn)題,隨著 Go Modules 的出現(xiàn),類似于內(nèi)部自簽發(fā)證書(shū)、安全審計(jì)等這些問(wèn)題也逐漸得到解決。


          筆者在騰訊當(dāng)前負(fù)責(zé)騰訊云在 Go 編程語(yǔ)言使用上的一些問(wèn)題, 2021年初開(kāi)始負(fù)責(zé)內(nèi)部 goproxy 服務(wù)并推廣Go Modules使用,這些技術(shù)支撐了騰訊云、微信、騰訊視頻、騰訊游戲、騰訊音樂(lè)、騰訊會(huì)議等明星產(chǎn)品,并與公司內(nèi)部軟件源團(tuán)隊(duì)、工蜂團(tuán)隊(duì)、TRPC 團(tuán)隊(duì)以及各個(gè) CI 團(tuán)隊(duì)達(dá)成密切的合作。在本系列文章中,筆者就將由淺入深幫助大家開(kāi)始學(xué)習(xí)和了解 Go Modules。

          Golang 開(kāi)發(fā)的模式演進(jìn)

          從 Go 出生開(kāi)始,用戶就一直在使用 GOPATH 這個(gè)環(huán)境變量,隨著 Go 語(yǔ)言的快速發(fā)展和不斷壯大,由 GOPATH 引起的編譯依賴問(wèn)題也開(kāi)始逐漸出現(xiàn)。終于在2019 年, Golang 迎來(lái) 10 周年之際,Google Go 團(tuán)隊(duì)終于開(kāi)始把目光投向了這一伴隨了 Golang 十年的環(huán)境變量

          GOPATH的使用

          目前在 Go 中存在兩種開(kāi)發(fā)模式,GOPATH mode 和 Go modules mode。


          在 Go modules 之前,Go 開(kāi)發(fā)中的依賴管理使用 GOPATH 開(kāi)發(fā)模式。在 GOPATH 開(kāi)發(fā)模式中,Go 命令使用 GOPATH 環(huán)境變量來(lái)實(shí)現(xiàn)以下幾個(gè)功能


          1. go install 命令安裝二進(jìn)制庫(kù)到 $GOBIN, 其默認(rèn)路徑為 $GOPATH/bin。

          2. go install 命令安裝編譯好的包到 $GOPATH/pkg/ 中,例如將 example.com/y/z 安裝到 $GOPATH/pkg/example.com/y/z.a。

          3. go get 命令下載源碼包到 $GOPATH/src/ 中,例如將 example.com/y/z 下載到 $GOPATH/src/example。

          Go modules的發(fā)展歷程

          GOPATH mode 開(kāi)發(fā)模式是終將要被淘汰的,Go 官方在整個(gè) Go 開(kāi)發(fā)生態(tài)系統(tǒng)中添加 package version 這一概念,進(jìn)而引入 Go modules 開(kāi)發(fā)模式。從 GOPATH mode 開(kāi)發(fā)模式變換到 Go modules 是一個(gè)漫長(zhǎng)的過(guò)程,它已經(jīng)經(jīng)歷了數(shù)個(gè) Go 的發(fā)行版本

          • Go 1.11 (2018 年 8 月) 引入了 GO111MODULE 環(huán)境變量,其默認(rèn)值為 auto。如果設(shè)置該變量 GO111MODULE=off, 那么 go 命令將始終使用 GOPATH mode 開(kāi)發(fā)模式。如果設(shè)置該變量 GO111MODULE=on,go 命令將始終使用 Go modules 開(kāi)發(fā)模式。如果設(shè)置該變量 GO111MODULE=auto (或者不設(shè)置),go 命令行會(huì)根據(jù)當(dāng)前工作目錄來(lái)決定使用哪種模式,如果當(dāng)前目錄在 $GOPATH/src 以外,并且在根目錄下存在 go.mod 文件,那么 go 命令會(huì)啟用 Go module 模式,否則使用 GOPATH 開(kāi)發(fā)模式。這個(gè)規(guī)則保證了所有在 $GOPATH/src 中使用 auto 值時(shí)原有編譯不受影響,并且還可以在其他目錄中來(lái)體驗(yàn)最新的 Go module 開(kāi)發(fā)模式。


          • Go 1.13 (2019 年 8 月) 調(diào)整了 GO111MODULE=auto 模式中對(duì) $GOPATH/src 的限制,如果一個(gè)代碼庫(kù)在 $GOPATH/src 中,并且有 go.mod 文件的存在, go 命令會(huì)啟用 module 開(kāi)發(fā)模式。這允許用戶繼續(xù)在基于導(dǎo)入的層次結(jié)構(gòu)中組織他們的檢出代碼,但使用模塊進(jìn)行個(gè)別倉(cāng)庫(kù)的導(dǎo)入。


          • Go 1.16 (2021 年 2 月) 會(huì)將 GO111MODULE=on 做為默認(rèn)值,默認(rèn)啟用 go module 開(kāi)發(fā)模式,也就是說(shuō),默認(rèn)情況下 GOPATH 開(kāi)發(fā)模式將被徹底關(guān)閉。如果用戶需要使用 GOPATH 開(kāi)發(fā)模式可以指定環(huán)境變量 GO111MODULE=auto 或者 GO111MODULE=off。


          • Go 1.NN (???) 將會(huì)廢棄 GO111MODULE 環(huán)境變量和 GOPATH 開(kāi)發(fā)模式,默認(rèn)完全使用 module 開(kāi)發(fā)模式。


          GOPATH 與Go modules的相愛(ài)想殺

          針對(duì)大家關(guān)心的幾個(gè)問(wèn)題,筆者對(duì)此作出如下回答:


          Q1:GOPATH 變量會(huì)被移除嗎?


          A:不會(huì),GOPATH 變量不會(huì)被移除。未來(lái)廢棄 GOPATH 開(kāi)發(fā)模式并不是指刪除 GOPATH 環(huán)境變量,它會(huì)繼續(xù)保留,主要作用如下:

          • go install 命令安裝二進(jìn)制到 $GOBIN 目錄,其默認(rèn)位置為 $GOPATH/bin。

          • go get 命令緩存下載的 modules 到 $GOMODCACHE 目錄,默認(rèn)位置為 $GOPATH/pkg/mod。

          • go get 命令緩存下載的 checksum 數(shù)據(jù)到 $GOPATH/pkg/sumdb 目錄。



          Q2:我還可以繼續(xù)在 `GOPATH/src/import/path` 中創(chuàng)建代碼庫(kù)嗎?


          A:可以,很多開(kāi)發(fā)者以這樣的文件結(jié)構(gòu)來(lái)組織自己的倉(cāng)庫(kù),你只需要在自己創(chuàng)建的倉(cāng)庫(kù)中添加 go.mod 文件。


          Q3:如果我想測(cè)試修改一個(gè)我需要的依賴庫(kù),我改怎么做?


          A:如果你編譯自己的項(xiàng)目時(shí)依賴了一些未發(fā)布的變更,你可以使用 go.mod 的 replace來(lái)實(shí)現(xiàn)你的需求。

          舉個(gè)例子,如果你已經(jīng)將 golang.org/x/website 和 golang.org/x/tools 下載到 $GOPATH/src/ 目錄下,那么你可以在 $GOPATH/src/golang.org/x/website/go.mod 中添加下面的指令來(lái)完成替換:

          replace golang.org/x/tools => $GOPATH/src/golang.org/x/tools

          當(dāng)然,replace 指令是不感知 GOPATH 的,將代碼下載到其他目錄也一樣可以。

          從0開(kāi)始使用 Go Modules


          1. 創(chuàng)建一個(gè)新的 Go module


          首先創(chuàng)建一個(gè)新目錄 /home/gopher/hello,然后進(jìn)入到這個(gè)目錄中,接著創(chuàng)建一個(gè)新文件, hello.go:

          package?hello

          func?Hello()?string?{

          ????return?"Hello,?world."

          }

          然后再寫(xiě)個(gè)對(duì)應(yīng)的測(cè)試文件 hello_test.go:

          package?hello

          import?"testing"

          func?TestHello(t?*testing.T)?{

          ????want?:=?"Hello,?world."

          ????if?got?:=?Hello();?got?!=?want?{

          ????????t.Errorf("Hello()?=?%q,?want?%q",?got,?want)

          ????}

          }


          現(xiàn)在我們擁有了一個(gè) package,但它還不是一個(gè) module,因?yàn)檫€沒(méi)有創(chuàng)建 go.mod 文件。如果在 /home/gopher/hello 目錄中執(zhí)行 go test,則可以看到:

          $ go test

          go: go.mod file not found in current directory or any parent directory; see 'go help modules'


          可以看到 Go 命令行提示沒(méi)有找到 go.mod 文件,可以參考 go help modules。這樣的話可以使用 Go mod init 來(lái)初始化一下,然后再執(zhí)行 Go test:

          $?go?mod?init?example.com/hello

          go:?creating?new?go.mod:?module?example.com/hello

          go:?to?add?module?requirements?and?sums:

          go?mod?tidy

          $go?mod?tidygo

          $?go?test

          PASS

          ok?example.com/hello??0.020s

          $

          這樣的話,module 測(cè)試就完成了。

          然后執(zhí)行的 go mod init 命令創(chuàng)建了一個(gè) go.mod 文件:

          $?cat?go.mod

          module?example.com/hello

          go?1.17


          2. 給 module 添加依賴


          Go modules 的主要亮點(diǎn)在于在編程時(shí)使用別人寫(xiě)的代碼,即引入一個(gè)依賴庫(kù)時(shí)能有非常好的體驗(yàn)。首先更新一下 hello.go,引入 rsc.io/quote 來(lái)實(shí)現(xiàn)一些新的功能。

          package?hello

          import?"rsc.io/quote"

          func?Hello()?string?{

          ????return?quote.Hello()

          }


          然后,再測(cè)試一下:

          $?go?test

          hello.go:3:8:?no?required?module?provides?package?rsc.io/quote;?to?add?it:

          go?get?rsc.io/quote

          $?go?get?rsc.io/quote

          go:?downloading?rsc.io/quote?v1.5.2

          go:?downloading?rsc.io/sampler?v1.3.0

          go:?downloading?golang.org/x/text?v0.0.0-20170915032832-14c0d48ead0c

          go:?added?golang.org/x/text?v0.0.0-20170915032832-14c0d48ead0c

          go:?added?rsc.io/quote?v1.5.2

          go:?added?rsc.io/sampler?v1.3.0

          $?go?test

          PASS

          ok?example.com/hello??1.401s


          從 Go 1.7開(kāi)始,Go modules 開(kāi)始使用 lazyloading 加載機(jī)制,依賴庫(kù)的更新需要根據(jù)提示手動(dòng)進(jìn)行相應(yīng)的更新。


          Go 命令會(huì)根據(jù) go.mod 的文件來(lái)解析拉取指定的依賴版本。如果在 go.mod 中沒(méi)有找到指定的版本,會(huì)提示相應(yīng)的命令引導(dǎo)用戶添加,然后 Go 命令會(huì)去解析最新的穩(wěn)定版本(Latest),并且添加到 go.mod 文件中。在這個(gè)例子中可以看到,第一次執(zhí)行的 Go test 運(yùn)行需要 rsc.io/quote 這個(gè)依賴,但是在 go.mod 文件中并沒(méi)有找到,于是引導(dǎo)用戶去獲取 latest 版本,用戶通過(guò) go get rsc.io/quote 獲取了最新版本 v1.5.2,而且還另外下載了另外兩個(gè) rsc.io/quote 需要的依賴:rsc.io/sampler 和 golang.org/x/text。間接依賴引用也會(huì)記錄在 go.mod 文件中,使用 indirect 注釋進(jìn)行標(biāo)記。


          $?cat?go.mod

          module?example.com/hello

          go?1.17

          require?(

          ????golang.org/x/text?v0.0.0-20170915032832-14c0d48ead0c?//?indirect

          ????rsc.io/quote?v1.5.2?//?indirect

          ????rsc.io/sampler?v1.3.0?//?indirect

          )


          再一次運(yùn)行 go test 命令不會(huì)重復(fù)上面的工作,因?yàn)?go.mod 已經(jīng)是最新的,并且所需的依賴包已經(jīng)下載到本機(jī)中了(在 $GOPATH/pkg/mod 中):

          $?go?test

          PASS

          ok?example.com/hello??0.020s


          注意,雖然 Go 命令可以快速輕松地添加新的依賴項(xiàng),但并非沒(méi)有代價(jià)。


          如上面所提到,在項(xiàng)目中添加一個(gè)直接依賴可能會(huì)引入其他間接依賴。go list -m all 命令可以列出當(dāng)前項(xiàng)目所依賴的所有依賴:

          $?go?list?-m?all

          example.com/hello

          golang.org/x/text?v0.0.0-20170915032832-14c0d48ead0c

          rsc.io/quote?v1.5.2

          rsc.io/sampler?v1.3.0


          在 go list 的輸出結(jié)果中,可以看到當(dāng)前的 module,也被稱為 main module 會(huì)展示在第一行,然后其他的會(huì)按照 module path 進(jìn)行排序。其中依賴 golang.org/x/text 的版本號(hào) v0.0.0-20170915032832-14c0d48ead0c 是一個(gè)偽版本號(hào), 它是 Go 版本的一種,指向了一個(gè)沒(méi)有打 tag 的 commit 上。


          另外除了 go.mod 文件,go 命令還維護(hù)了一個(gè)叫做 go.sum 的文件,這個(gè)文件包含了每個(gè)版本對(duì)應(yīng)的加密哈希值。

          $?cat?go.sum

          golang.org/x/text?v0.0.0-20170915032832-14c0d48ead0c?h1:qgOY6WgZO...

          golang.org/x/text?v0.0.0-20170915032832-14c0d48ead0c/go.mod?h1:Nq...

          rsc.io/quote?v1.5.2?h1:w5fcysjrx7yqtD/aO+QwRjYZOKnaM9Uh2b40tElTs3...

          rsc.io/quote?v1.5.2/go.mod?h1:LzX7hefJvL54yjefDEDHNONDjII0t9xZLPX...

          rsc.io/sampler?v1.3.0?h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/Q...

          rsc.io/sampler?v1.3.0/go.mod?h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9...


          Go 命令使用 go.sum 來(lái)保證每次下載的依賴庫(kù)代碼和第一次都是一致的,進(jìn)而來(lái)保證項(xiàng)目不會(huì)出現(xiàn)一些異常情況,所以 go.mod 和 go.sum 都應(yīng)該上傳到 git 等版本控制系統(tǒng)中。


          3. 更新依賴


          從上面 go list -m all 命令的輸出中,可以看到在庫(kù) golang.org/x/text 中使用了一個(gè)偽版本號(hào)。首先把這個(gè)版本好更新到最新的穩(wěn)定版本:


          $?go?get?golang.org/x/text

          go:?downloading?golang.org/x/text?v0.3.7

          go:?upgraded?golang.org/x/text?v0.0.0-20170915032832-14c0d48ead0c?=>?v0.3.7

          $?go?test

          PASS

          ok?example.com/hello??0.013s


          測(cè)試仍然可以通過(guò),然后再執(zhí)行一次 go list -m all:

          $?go?list?-m?all

          example.com/hello

          golang.org/x/text?v0.3.7

          rsc.io/quote?v1.5.2

          rsc.io/sampler?v1.3.0

          $?cat?go.mod

          module?example.com/hello

          go?1.17

          require?(

          ????golang.org/x/text?v0.3.7?//?indirect

          ????rsc.io/quote?v1.5.2?//?indirect

          ????rsc.io/sampler?v1.3.0?//?indirect

          )


          結(jié)語(yǔ)


          Go 通過(guò) Go modules 的依賴管理統(tǒng)一了 Go 生態(tài)中眾多的第三方的依賴管理,并且高度集成在 Go 命令行中,無(wú)需開(kāi)發(fā)者們額外安裝使用,目前在當(dāng)前維護(hù)的 Go 版本中都已經(jīng)支持了 Go modules。還沒(méi)有切換到 Go modules 的用戶,強(qiáng)烈建議大家開(kāi)始使用它,這無(wú)論是從團(tuán)隊(duì)開(kāi)發(fā)體驗(yàn)、性能還是安全等方面,都能提供諸多的優(yōu)質(zhì)特性和保障。



          想要了解更多有關(guān) Go 語(yǔ)言的資訊動(dòng)態(tài),還可通過(guò)掃描下方二維碼,進(jìn)去一起探討交流哦~



          瀏覽 36
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  中文字幕第9页 | 国模无码在线 | 久久大香蕉网 | 亚洲视频在线免费观 | 网站黄色日韩在线看 |