<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 Modules基礎(chǔ)精進(jìn),六大核心概念全解析(下)

          共 5246字,需瀏覽 11分鐘

           ·

          2021-12-13 09:28


          導(dǎo)語?|?騰訊云加社區(qū)精品內(nèi)容欄目《云薦大咖》,特邀行業(yè)佼者,聚焦前沿技術(shù)的落地與理論實(shí)踐,持續(xù)為您解讀云時(shí)代熱點(diǎn)技術(shù),探秘行業(yè)發(fā)展新機(jī)。



          在上篇《Go Modules基礎(chǔ)精進(jìn),六大核心概念全解析(上)》中,我們介紹了模塊路徑、版本號與兼容性原則、偽版本號三大概念,而在下篇我們將會繼續(xù)介紹Go Modules核心概念


          四、主版本號后綴


          從主版本號2開始,模塊路徑中必須添加一個(gè)像/v2這樣的一個(gè)和主版本號匹配的后綴。舉個(gè)例子如果一個(gè)模塊在版本v1.0.0是的路徑為example.com/test,那么它在v2.0.0時(shí)的路徑將是example.com/test/v2。


          主版本號后綴遵循導(dǎo)入兼容規(guī)則:如果一個(gè)新代碼包和老代碼包擁有同樣的導(dǎo)入路徑,那么新包必須保證對老代碼包的向后兼容


          • 根據(jù)定義,模塊的新主版本中的包與先前主版本中的相應(yīng)包不向后兼容。因此,從v2開始,包需要新的導(dǎo)入路徑。這是通過向模塊路徑添加主版本后綴來實(shí)現(xiàn)的。由于模塊路徑是模塊內(nèi)每個(gè)包的導(dǎo)入路徑的前綴,因此將主版本后綴添加到模塊路徑可為每個(gè)不兼容的版本提供不同的導(dǎo)入路徑。


          • 主版本v0或v1不允許使用主版本后綴。v0和v1之間的模塊路徑不需要更改,因?yàn)関0版本為不穩(wěn)定,沒有兼容性保證。此外,對于大多數(shù)模塊,v1向后兼容最新的v0版本,v1版本才開始作為對兼容性的承諾。


          • 這里有一個(gè)特例,以gopkg.in/開頭的模塊路徑必須始終具有主版本后綴,即使是v0和v1版本。后綴必須以點(diǎn)而不是斜線開頭(例如,gopkg.in/yaml.v2)。因?yàn)樵贕o Modules推出之前,gopkg.in就沿用了這個(gè)規(guī)則,為了能讓引入gopkg.in包的代碼能繼續(xù)導(dǎo)入編譯,Go做了一些兼容性工作。


          • 主版本后綴可以讓一個(gè)模塊的多個(gè)主版本共存于同一個(gè)構(gòu)建中。這可以很好的解決鉆石依賴性問題(diamond dependency conflict) https://jlbp.dev/what-is-a-diamond-dependency-conflict。通常,如果傳遞依賴項(xiàng)在兩個(gè)不同版本中需要一個(gè)模塊,則將使用更高的版本。但是,如果兩個(gè)版本不兼容,則任何一個(gè)版本都不會滿足所有的調(diào)用者。由于不兼容的版本必須具有不同的主版本號,因此主版本后綴具有不同的模塊路徑,這樣就不存在沖突了:具有不同后綴的模塊被視為單獨(dú)的模塊,并且它們的包的導(dǎo)入路徑也是不同的。


          • 因?yàn)楹芏郍o項(xiàng)目在遷移到Go模塊之前就發(fā)布了v2或更高版本的版本,所以沒有使用主要版本后綴。對于這些版本,Go使用+incompatible 構(gòu)建標(biāo)記來進(jìn)行注釋(例如,v2.0.0+incompatible)。



          五、解析包路徑到模塊路徑的流程


          通常在使用“go get”時(shí)可能是指定到一個(gè)包路徑,而非模塊路徑,Go是如何找到模塊路徑的呢?


          go命令會在主模塊(當(dāng)前模塊)的build list中搜索有哪些模塊路徑匹配這個(gè)包路徑的前綴。舉個(gè)例子,如果導(dǎo)入的包路徑是example.com/a/b,發(fā)現(xiàn)example.com/a是一個(gè)模塊路徑,那么就會去檢查example.com/a在 b目錄中是否包含這個(gè)包,在這個(gè)目錄中要至少存在一個(gè)go源碼文件才會被認(rèn)為是一個(gè)有效的包。編譯約束(Build Constraints)在這一過程中不會被應(yīng)用。如果確實(shí)在build list中找到了一個(gè)模塊包含這個(gè)包,那么這個(gè)模塊將被使用。如果沒有發(fā)現(xiàn)模塊能提供這個(gè)包或者發(fā)現(xiàn)兩個(gè)及兩個(gè)以上的模塊提供了這個(gè)包,那么go命令會提示報(bào)錯。但是你可以指定-mod=mod來使go命令嘗試下載本地找不到的包,并且更新go.mod和go.sum。go get和go mod tidy這兩個(gè)命令會自動的做這些工作。


          當(dāng)go命令試圖下載一個(gè)新的代碼包時(shí),它回去檢查GOPROXY環(huán)境變量,這是一個(gè)使用逗號分隔的URL列表,當(dāng)然也支持像direct和off這樣的關(guān)鍵字。代理URL代表go將使用GOPROXY協(xié)議拉取模塊,direct表示go需要和版本控制系統(tǒng)直接交互,off不需要和外界做任何交互。另外,GOPRIVATE和GONOPROXY環(huán)境變量也可以精細(xì)的控制go下載代碼包的策略。


          對于GOPROXY列表中的每一項(xiàng),go命令回去請求模塊路徑的每一個(gè)前綴。對于請求成功的模塊,go命令回去下載最新模塊并且檢查這個(gè)某塊是否包含請求的包。如果多個(gè)模塊包含了請求的包,擁有最長路徑的將被選擇。如果發(fā)現(xiàn)的模塊中沒有包含這個(gè)包,會報(bào)錯。如果沒有模塊被發(fā)現(xiàn),go命令會嘗試GOPROXY列表中的下一個(gè)配置項(xiàng),如果最終都嘗試過沒有發(fā)現(xiàn)則會報(bào)錯。舉個(gè)例子,假設(shè)用戶想要去獲取golang.org/x/net/html這個(gè)包,之前配置的GOPROXY為https://corp.example.com,https://goproxy.iogo命令會遵循下面的請求順序:


          向 https://corp.example.com/ 發(fā)起請求 (并行):Request for latest version of golang.org/x/net/htmlRequest for latest version of golang.org/x/netRequest for latest version of golang.org/xRequest for latest version of golang.org


          如果https://corp.example.com/上面都失敗了返回410或者404狀態(tài)碼,向https://proxy.golang.org/發(fā)起請求:


          Request for latest version of golang.org/x/net/htmlRequest for latest version of golang.org/x/netRequest for latest version of golang.org/xRequest for latest version of golang.org


          當(dāng)一個(gè)需要的模塊被發(fā)現(xiàn)后,go命令會將這個(gè)依賴模塊的路徑和對應(yīng)版本添加到主模塊的go.mod文件中。這樣就確保了以后在編譯該模塊時(shí),同樣的模塊版本將被使用,保證了編譯的可重復(fù)性。如果解析的代碼包沒有被主模塊直接引用,在go.mod文件中添加的新依賴后會有//indirect注釋。



          六、go.mod文件


          就像前面提到過的,模塊的定義是由一個(gè)UTF-8編碼的名為go.mod文本文件定義的。這個(gè)文件是按照“行”進(jìn)行組織的(line-oriented)。每一行都有一個(gè)獨(dú)立的指令,有一個(gè)預(yù)留關(guān)鍵字和一些參數(shù)組成。比如:


          module example.com/my/thinggo 1.17require example.com/other/thing v1.0.2require example.com/new/thing/v2 v2.3.4exclude example.com/old/thing v1.2.3replace example.com/bad/thing v1.4.5 => example.com/good/thing v1.4.5retract [v1.9.0, v1.9.5]


          開頭的關(guān)鍵詞可以以行的形式被歸總為塊,就像日常所用的imports一樣,所以可以改成下面這樣:


          require ( example.com/new/thing/v2 v2.3.4 example.com/old/thing v1.2.3)


          go.mod文件的設(shè)計(jì)兼顧了開發(fā)者的可讀性和機(jī)器的易寫性。go命令也提供了幾個(gè)子命令來幫組開發(fā)者修改go.mod文件。舉個(gè)例子,go get命令可以在需要的時(shí)候更新go.mod文件。go mod edit命令可以對文件做一些底層的修改操作。如果我們也有類似的需求,可以使用golang.org/x/mod/modfile包以編程方式進(jìn)行同樣的更改。通過這個(gè)包,也可以一窺底層go.mod的struct結(jié)構(gòu):


          // go.mod 文件的組成形式type File struct { Module *Module  // 模塊路徑 Go *Go  // Go 版本 Require []*Require // 依賴模塊 Exclude []*Exclude // 排除模塊 Replace []*Replace // 替換模塊 Retract []*Retract // 撤回模塊}// A Module is the module statement.type Module struct { Mod module.Version Deprecated string}// A Go is the go statement.type Go struct { Version string // "1.23"}// An Exclude is a single exclude statement.type Exclude struct { Mod module.Version}// A Replace is a single replace statement.type Replace struct { Old module.Version New module.Version}// A Retract is a single retract statement.type Retract struct { VersionInterval Rationale string}


          從上面的Module的struct中可以看到“Deprecated”這一結(jié)構(gòu),在Go Modules推出的早期是沒有這個(gè)設(shè)計(jì)的,那么這個(gè)字段是做什么用的呢?估計(jì)很多人都不知道,如果我們維護(hù)的一個(gè)模塊主版本從v1演進(jìn)到了v2,而不再維護(hù)v1版本了,希望用戶盡可能使用v2,通過上面的介紹知道v1和v2是不同的import path,“Retract”也無能為力,這時(shí)候這個(gè)“Deprecated”就起作用了,看下面的例子:


          // Deprecated: in example.com/a/[email protected], the latest supported version is example.com/a/b/v2.module example.com/a/bgo 1.17


          當(dāng)用戶再去獲取example.com/a/b這個(gè)版本時(shí),go命令可以感知到這個(gè)版本已經(jīng)不再維護(hù)了,會報(bào)告給用戶:


          go get -d example.com/a/b@v1.9.0go: warning: module example.com/deprecated/a is deprecated: in example.com/a/b@v1.9.0, the latest supported version is example.com/a/b/v2


          用戶就可以根據(jù)提示進(jìn)行v2代碼拉取了。


          Go Modules基礎(chǔ)精進(jìn),六大核心概念全解析(上)》一文全面介紹了Go Modules中的模塊、模塊路徑、包、包路徑、如何通過包路徑尋找模塊路徑,還介紹了版本號和偽版本號,最后簡單介紹了go.mod文件,以及其中不為人知的“Deprecated”功能,了解這些概念、設(shè)計(jì)理念和兼容性原則,將對管理和維護(hù)自己的Go模塊大有幫助。


          以上這些概念都是平常使用Go語言會高頻接觸到的內(nèi)容,理解版本號和偽版本號的區(qū)別和設(shè)計(jì)原則,可以幫助我們清楚按照semver的標(biāo)準(zhǔn)定義自己的tag是多么重要。同時(shí),遵循Go Modules定義的兼容性原則,上下游開發(fā)者在社區(qū)協(xié)同時(shí)將會變得更加友好和高效。接下來的系列文章將會開始具體來了解Go Modules中的設(shè)計(jì)細(xì)節(jié),例如go.mod文件詳解以及配套的go mod子命令等,敬請期待。另外,騰訊云goproxy企業(yè)版已經(jīng)產(chǎn)品化,需要了解的同學(xué)可以跳轉(zhuǎn)↓↓

          (https://goproxy.io/zh/docs/enterprise.html)



          ?推薦閱讀


          Go Modules基礎(chǔ)精進(jìn),六大核心概念全解析(上)

          Go語言重新開始,Go Modules的前世今生與基本使用

          聊聊代碼質(zhì)量-《學(xué)得會,抄得走的提升前端代碼質(zhì)量方法》前言

          鏈路追蹤(Tracing)的前世今生(上)



          ??「閱讀原文」一鍵訂閱《云薦大咖》專欄,看云端技術(shù)起落,聽大咖指點(diǎn)迷津!云薦官將在每周五抽取部分訂閱小伙伴,送出云加視頻禮盒

          瀏覽 52
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

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

          手機(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>
                  国产熟妇XXXXXⅩ性Ⅹ交 | 青娱乐免费精品视频1 | 亚洲乱亚洲乱妇 | 亚州无码高清视频 | 红桃视频亚洲 |