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

Go 語言做開發(fā)時,路徑是如何定義的?Go Mudules又為此帶來了哪些改變?本文將會全面介紹Go modules六大核心概念,包括了設(shè)計理念與兼容性原則等,掌握這些技術(shù)點對于管理和維護Go 模塊有重要價值。
上一篇文章中,筆者介紹了如何以經(jīng)典的 hello world 為例創(chuàng)建一個 Go module 模塊,需要說明的是一個模塊中是可以包含多個包(package)的,它們是可以被一起發(fā)布、打包、版本化的。同時,Go Modules 也可以通過版本管理系統(tǒng)(github、gitlab)或者 goproxy 代理進行下載。在使用 Go Modules 之前,建議大家弄清楚息息相關(guān)的六大核心概念,以方便大家在后期的開發(fā)、使用過程中理解更加深入。
我們在使用 Go 語言做開發(fā)時經(jīng)常會遇到像 “example.com/test” 或者 “example.com/test/pkg/log”這樣的路徑,這些路徑到底是怎么定義的,兩者中存在什么關(guān)系,在 Go Modules 中又扮演著怎樣的角色呢?Go Modules 的引入對已有的包又引入了哪些新的概念,它們是如何協(xié)作的?對兼容性提出了哪些新的要求呢?讓我們一起來看一下。
一:模塊路徑 (Module Path)
Go 使用 “module path” 來區(qū)分不同的 module 模塊,它在 go.mod 文件中被定義,這個文件中還包含了這個模塊編譯所需的其他依賴。如果一個目錄中包含了 go.mod 文件,那么這個目錄就是這個 Go 模塊的根目錄了。
另外,還要介紹下包(package) 這個概念,它在 Go Modules 出現(xiàn)之前就已經(jīng)存在了。Go 模塊中的 “包 (package)”是處于同一目錄中的一些源代碼文件的集合,這些文件將被編譯在一起。“包路徑(package path)”是模塊路徑和子目錄(模塊根目錄的相對路徑)的組合。舉個例子,在模塊“golang.org/x/net”下的 html 目錄中有個包,這個包的路徑是 “golang.org/x/net/html”。
總結(jié)下來就是:一個代碼倉庫可以包含多個 Go 模塊,一個 Go 模塊可以包含多個 Go 包。
模塊路徑是一個 Go 模塊的規(guī)范名稱,用于區(qū)分不通的模塊。同時他還是該模塊下 Go 包的路徑前綴。理論上,模塊路徑應(yīng)該至少包含兩個關(guān)鍵信息:
模塊的作用哪里獲取該模塊
二:版本號與兼容性原則
版本號相當(dāng)于是一個模塊的只讀快照,它可以是正式的發(fā)布版本,也可以是預(yù)發(fā)布版本。每個版本都以字母 v 開頭,后跟一個語義版本,例如 v1.0.0。
總而言之,語義版本由三個由點分隔的非負(fù)整數(shù)(主要版本、次要版本和補丁版本,從左到右)組成。 補丁版本后可以跟一個以連字符開頭的可選預(yù)發(fā)布字符串。預(yù)發(fā)布字符串或補丁版本后可以跟一個以加號開頭的構(gòu)建元數(shù)據(jù)字符串。例如,v0.0.0、v1.12.134、v8.0.5-pre、v2.0.9+meta 等都是有效版本。
版本號中的信息代表了這個版本是否是一個穩(wěn)定版,是否保持了與之前版本的兼容性。
如果一個版本的主版本號是 0 或者它有一個預(yù)發(fā)布版本后綴,那么這個版本被認(rèn)為是一個不穩(wěn)定版本。通常,不穩(wěn)定版本不受兼容性限制的,舉個例子,v0.2.0 可能和 v0.1.0 是不兼容的,v1.5.0-beta 可能和 v1.5.0 也是不兼容的。
Go 可以通過 tags、分支、和 commit 哈希值來獲取模塊,即使這些命名沒有遵循這些規(guī)則。在主模塊中,go 命令會自動的將這些 revision 轉(zhuǎn)化為符合標(biāo)準(zhǔn)的版本號,其被稱為偽版本號(pseudo-version)。舉個例子,當(dāng)執(zhí)行下面的命令時:
go?get?-d?golang.org/x/net@daa7c041Go 會講指定的 hash daa7c041 轉(zhuǎn)化為一個偽版本號 v0.0.0-20191109021931-daa7c04131f5。在主模塊之外需要規(guī)范版本,如果 go.mod 文件中出現(xiàn)像 master 這樣的非規(guī)范版本,go 命令會報錯。
三:偽版本號
偽版本號是一種預(yù)發(fā)布版本號的格式,其中包含了指定的 commit hash 值。另外,對于沒有打標(biāo)簽的代碼庫,也可以使用偽版本號來表明某個版本,它可以在正式發(fā)布某個版本之前方便的進行測試。舉個例子,每個偽版本號都有三部分組成:
在這三個部分之下,又分為以下多種情況
偽版本號不需要手動指定。很多 Go 命令可以接受一個 commit hash 或者分支名,然后自動將其轉(zhuǎn)化為一個偽版本號(或者一個標(biāo)簽,如果存在的話)。例如:
go?get?-d?example.com/mod@master
go?list?-m?-json?example.com/mod@abcd1234在本篇中,我們介紹了模塊路徑、版本號與兼容性原則、偽版本號三大概念,而在下篇我們將會繼續(xù)介紹Go Modules核心概念,包括主版本號后綴、解析包路徑到模塊路徑的流程、go.mod 文件,敬請期待。另外,騰訊云 goproxy 企業(yè)版已經(jīng)產(chǎn)品化,需要了解的同學(xué)可以點擊這里(https://goproxy.io/zh/docs/enterprise.html)。
偽版本號會高于這些已經(jīng)存在的基礎(chǔ)版本號,但是會低于后面生成的其他偽版本號。
有相同基礎(chǔ)版本前綴的偽版本按時間順序排序。
如果之前沒有基版本,那么諸如 vX.0.0-yyyymmddhhmmss-abcdefabcdef 這樣的偽版本號將被啟用。主版本號 X 需要匹配模塊的主版本號后綴。 如果之前的基版本號是一個像 vX.Y.Z-pre 這樣的預(yù)發(fā)布版本,那么 vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef 將被采用。 如果之前的基版本號是一個像 vX.Y.Z 這樣的正式版本,那么 vX.Y.(Z+1)-0.yyyymmddhhmmss-abcdefabcdef 將被采用,舉個例子,如果基版本號是 v1.2.3,偽版本號可能是 v1.2.4-0.20191109021931-daa7c04131f5。 基于不同的基礎(chǔ)版本號,多個偽版本號是有可能指向同一個 commit hash 的,在對一個低于已經(jīng)存在的偽版本號打標(biāo)簽時,這種情況就會發(fā)生。上面介紹的這種偽版本號攜帶了兩個非常有用的信息: 基本版本前綴(vX.0.0 或 vX.Y.Z-0),它要么源自修訂版之前的語義版本標(biāo)簽,要么源自 vX.0.0(如果沒有此類標(biāo)簽)。 時間戳 (yyyymmddhhmmss),這是創(chuàng)建 commit 的 UTC 時間。在 Git 中,這是 commit 提交時間。 commit 標(biāo)識符 (abcdefabcdef),它是提交 commit 哈希的 12 個字符的前綴,或者在 Subversion 中,是一個用零填充的修訂號。 當(dāng)維護的模塊發(fā)生了一些不兼容變更,比如修改了外部可調(diào)用的接口或者函數(shù)時,需要對主版本號進行遞增,并且將次版本號和補丁版本號置為零。比如在模塊中移除了一個包。 在模塊中添加一些新的函數(shù)或者接口,并沒有影響模塊的兼容性時,需要對次版本號進行遞增,并且將補丁版本號置為零。 當(dāng)修復(fù)了一些 bug 或者進行了一些優(yōu)化時,只需要對補丁版本號進行遞增就可以了,因為這些變更不會對已經(jīng)公開的接口進行變更。 預(yù)發(fā)布后綴代表了這個版本號是一個預(yù)發(fā)布版本。預(yù)發(fā)布版本號的排序會在正式版本號的前面。舉個例子,v1.2.3-pre 會排列在 v1.2.3 前面。 元數(shù)據(jù)后綴會在版本比對中被忽略,版本控制中的代碼庫會忽略帶有構(gòu)建元數(shù)據(jù)的標(biāo)簽,但在 go.mod 文件中指定的版本中會保留構(gòu)建元數(shù)據(jù)。如果一個模塊還沒有遷移到 Go Modules 并且主版本號是 2 或者更高,+incompatible 后綴會被添加到版本號上。

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