Go 依赖管理
Golang包管理工具glide簡(jiǎn)介
前言
Golang是一個(gè)十分有趣,簡(jiǎn)潔而有力的開發(fā)語(yǔ)言,用來(lái)開發(fā)并發(fā)/并行程序是一件很愉快的事情。在這里我感受到了其中一些好處:
- 沒有少了許多代碼格式風(fēng)格的爭(zhēng)論,強(qiáng)制統(tǒng)一的風(fēng)格多好;
- 編譯速度超快,再也不用等待許久,才能編譯完工程(測(cè)試驅(qū)動(dòng)開發(fā)自然更爽);
- 也不會(huì)出現(xiàn)同一個(gè)項(xiàng)目組中的人,在使用同一個(gè)語(yǔ)言的不同子集。但這種情況不論是在C#還是在Java的世界里,都還是普遍存在的;
- 輕松跨平臺(tái)(當(dāng)然Java做得不錯(cuò),C#/.net還是努力中...)
- 這是一門非常簡(jiǎn)潔、簡(jiǎn)單、清晰的編程語(yǔ)言(關(guān)鍵字好少啊)
- 包依賴處理得很有趣;
- 錯(cuò)誤處理機(jī)制很有趣,個(gè)人覺得比C#/Java的異常處理機(jī)制更方便,也更合理些;
- 對(duì)面向?qū)ο缶幊毯苡腥?#xff0c;非侵入性的接口實(shí)現(xiàn)方式,太贊了。
- 用組合而不是繼承
有些東西沒有,比如模板,這個(gè)東西有一大片爭(zhēng)論,官方也有明確的回應(yīng)。是啊,為什么一定要模板呢?非要不可嗎?這么關(guān)鍵嗎?如果非要不可,是不是go并不是這個(gè)環(huán)境下的最佳選擇呢。
還有一個(gè)問(wèn)題的是包管理,并沒有官方最佳管理方案,在go的世界里存在大量的自制解決方案。go語(yǔ)言的包是沒有中央庫(kù)統(tǒng)一管理的,通過(guò)使用go get命令從遠(yuǎn)程代碼庫(kù)(github.com,goolge code 等)拉取,直接跳過(guò)中央版本庫(kù)的約束,讓代碼的拉取直接基于源代碼版本控制庫(kù),開發(fā)者間的協(xié)同直接依賴于源代碼的版本控制。直接去除了庫(kù)版本的概念。沒有明顯的包版本標(biāo)識(shí),感覺還是有點(diǎn)不適應(yīng),官方的建議是把外部依賴的代碼全部復(fù)制到自己可控的源代碼庫(kù)中,進(jìn)行同意管理。從而做到對(duì)依賴包的可控管理。
1.5版本的vendor目錄特性后,官方wiki推薦了多種支持這種特性的包管理工具如:Godep、gv、gvt、glide、Govendor等。我比較喜歡glide。此外,作為程序員FQ似乎是必備技能,翻得一手好墻,才能跟得上步伐,才有收起刀落的手感,怎一個(gè)爽字了得。別問(wèn)我怎么FQ,找度娘,她知道。
glide
glide是Go的包管理工具。支持語(yǔ)義化版本,支持Git、Svn等,支持Go工具鏈,支持vendor目錄,支持從Godep、GB、GPM、Gom倒入,支持私有的Repos和Forks。
使用glide管理的工程目錄結(jié)構(gòu)如下:
- $GOPATH/src/myProject (Your project)||-- glide.yaml||-- glide.lock||-- main.go (Your main go code can live here)||-- mySubpackage (You can create your own subpackages, too)| || |-- foo.go||-- vendor|-- github.com||-- Masterminds||-- ... etc.安裝
$ curl https://glide.sh/get | sh初始化
$ glide init初始化,glide掃描代碼目錄,創(chuàng)建一個(gè)glide.yaml文件,文件中記錄了所有的依賴
編輯配置
$ edit glide.yaml通過(guò)修改glide.yaml文件,可以添加版本信息等,這一步不是必須的。
解析下載包依賴
$ glide update或者
$ glide up下載和更新glide.yaml中列出的所有依賴包,并將它們放到vendor目錄下。glide同時(shí)也遞歸獲取依賴包需要的任何依賴項(xiàng)包括配置文件中定義的依賴項(xiàng)目。glide遞歸獲取依賴,可以識(shí)別Glide、Godep、gb、gom和GPM管理的項(xiàng)目。
當(dāng)依賴被制定到特定的版本時(shí),名為glide.lock的文件會(huì)被創(chuàng)建或者更新。例如,如果在glide.yaml中一個(gè)版本被指定在一個(gè)范圍內(nèi)(如:^1.2.3),那么glide將在glide.yaml中設(shè)定一個(gè)特定提交ID(commit id)。如此,將允許重復(fù)安裝(見 glide install命令)。
從獲取的依賴包中移除嵌套的vendor/目錄可以使用-v標(biāo)記。
安裝特定版本
當(dāng)需要從glide.lock文件中安裝制定版本的包是,可以使用install命令:
glide install該命令將會(huì)讀取glide.lock文件,當(dāng)glide.lock文件和glide.yaml不同步時(shí),如glide.yaml發(fā)生改變,glide將會(huì)提供一個(gè)警告。運(yùn)行g(shù)lide up命令更新依賴樹時(shí),將會(huì)重建glide.lock文件。
查看glide.yaml中依賴名稱
$ glide name查看依賴列表
$ glide list查看幫助
$ glide help參看glide版本信息
$ glide --version無(wú)論何種語(yǔ)言,依賴管理都是一個(gè)比較復(fù)雜的問(wèn)題。而Go語(yǔ)言中的依賴管理機(jī)制目前還是讓人比較失望的。在1.6版本之前,官方只有把依賴放在GOPATH中,并沒有多版本管理機(jī)制;1.6版本(1.5版本是experimental feature)引入vendor機(jī)制,是包依賴管理對(duì)一次重要嘗試。他在Go生態(tài)系統(tǒng)中依然是一個(gè)熱門的爭(zhēng)論話題,還沒有想到完美的解決方案。
看其它
我們先來(lái)看看其它語(yǔ)言怎么解決,例舉兩種典型的管理方式:
Java
開發(fā)態(tài),可以通過(guò)maven和gradle工具編輯依賴清單列表/腳本,指定依賴庫(kù)的位置/版本等信息,這些可以幫助你在合適的時(shí)間將項(xiàng)目固化到一個(gè)可隨時(shí)隨地重復(fù)編譯發(fā)布的狀態(tài)。這些工具對(duì)我來(lái)說(shuō)已經(jīng)足夠優(yōu)雅有效。但maven中也有不同依賴庫(kù)的內(nèi)部依賴版本沖突等令人心煩的問(wèn)題。尤其是在大型項(xiàng)目中的依賴傳遞問(wèn)題,若團(tuán)隊(duì)成員對(duì)maven機(jī)制沒有足夠了解下,依賴scope的濫用,會(huì)讓整個(gè)項(xiàng)目工程的依賴樹變得特別的巨大而每次編譯效率低下。運(yùn)行態(tài),目前Java也沒有很好的依賴管理機(jī)制,雖有classloader可以做一定的隔離,但像OSGi那種嚴(yán)格的版本管理,會(huì)讓使用者陷入多版本相互沖突的泥潭。
Node.js
npm是Node.js的首選模塊依賴管理工具。npm通過(guò)一個(gè)當(dāng)前目錄的 package.json 文件來(lái)描述模塊的依賴,在這個(gè)文件里你可以定義你的應(yīng)用名稱( name )、應(yīng)用描述( description )、關(guān)鍵字( keywords )、版本號(hào)( version )等。npm會(huì)下載當(dāng)前項(xiàng)目依賴模塊到你項(xiàng)目中的一個(gè)叫做node_modules的文件夾內(nèi)。與maven/gradle不同的是,maven最終會(huì)分析依賴樹,把相同的軟件默認(rèn)扁平化取最高版本。而npm支持nested dependency tree。nested dependency tree是每個(gè)模塊依賴自己目錄下node_modules中的模塊,這樣能避免了依賴沖突, 但耗費(fèi)了更多的空間和時(shí)間。由于Javascript是源碼發(fā)布,所以開發(fā)態(tài)與運(yùn)行態(tài)的依賴都是基于npm,優(yōu)先從自己的node_modules搜索依賴的模塊。
go get
Go對(duì)包管理一定有自己的理解。對(duì)于包的獲取,就是用go get命令從遠(yuǎn)程代碼庫(kù)(GitHub, Bitbucket, Google Code, Launchpad)拉取。這樣做的好處是,直接跳過(guò)了包管理中央庫(kù)的的約束,讓代碼的拉取直接基于版本控制庫(kù),大家的協(xié)作管理都是基于這個(gè)版本依賴庫(kù)來(lái)互動(dòng)。細(xì)體會(huì)下,發(fā)現(xiàn)這種設(shè)計(jì)的好處是去掉冗余,直接復(fù)用最基本的代碼基礎(chǔ)設(shè)施。Golang這么干很大程度上減輕了開發(fā)者對(duì)包管理的復(fù)雜概念的理解負(fù)擔(dān),設(shè)計(jì)的很巧妙。
當(dāng)然,go get命令,仍然過(guò)于簡(jiǎn)單。對(duì)于現(xiàn)實(shí)過(guò)程中的開發(fā)者來(lái)說(shuō),仍然有其痛苦的地方:
- 缺乏明確顯示的版本。團(tuán)隊(duì)開發(fā)不同的項(xiàng)目容易導(dǎo)入不一樣的版本,每次都是get最新的代碼。尤其像我司對(duì)開源軟件管理非常嚴(yán)格,開源申請(qǐng)幾乎是無(wú)法實(shí)施。
- 第三方包沒有內(nèi)容安全審計(jì),獲取最新的代碼很容易引入代碼新的Bug,后續(xù)運(yùn)行時(shí)出了Bug需要解決,也無(wú)法版本跟蹤管理。
- 依賴的完整性無(wú)法校驗(yàn),基于域名的package名稱,域名變化或子路徑變化,都會(huì)導(dǎo)致無(wú)法正常下載依賴。我們?cè)谑褂眠^(guò)程,發(fā)現(xiàn)還是有不少間接依賴包的名稱已失效了(不存在,或又fork成新的項(xiàng)目,舊的已不存維護(hù)更新)。
而Go官方對(duì)于此類問(wèn)題的建議是把外部依賴的代碼復(fù)制到你的?源碼庫(kù)中管理?。把第三方代碼引入自己的代碼庫(kù)仍然是一種折中的辦法,對(duì)于像我司的軟件開發(fā)流程來(lái)說(shuō),是不現(xiàn)實(shí)的:
- 開源掃描會(huì)掃描出是相似的代碼時(shí),若License不是寬松的,則涉及到法律風(fēng)險(xiǎn),若是寬松的,開源掃描認(rèn)證確認(rèn)工作也很繁瑣。
- 如何升級(jí)版本,代碼復(fù)制過(guò)來(lái)之后,源始的項(xiàng)目的代碼可以變化很大了,無(wú)明顯的版本校驗(yàn),借助工具或腳本來(lái)升級(jí)也會(huì)帶來(lái)工作量很大。
- 復(fù)制的那一份代碼已經(jīng)開始變成私有,第三方代碼的Bug只能自己解決,難以貢獻(xiàn)代碼來(lái)修復(fù)Bug,或通過(guò)推動(dòng)社區(qū)來(lái)解決。
- 普通的程序問(wèn)題可能不是很大問(wèn)題,最多就是編譯時(shí)的依賴。但如果你寫的是一個(gè)給其他人使用的lib庫(kù),引入這個(gè)庫(kù)就會(huì)帶來(lái)麻煩了。你這個(gè)庫(kù)被多人引用,如何管理你這個(gè)庫(kù)的代碼依賴呢?
好在開源的力量就是大,Go官方?jīng)]有想清楚的版本管理問(wèn)題,社區(qū)就會(huì)有人來(lái)解決,我們已經(jīng)可以找到許多不錯(cuò)的解決方案,不妨先參考下?官方建議?。
vendor機(jī)制
vendor是1.5引入為體驗(yàn),1.6中正式發(fā)布的依賴管理特性。Go團(tuán)隊(duì)在推出vendor前已經(jīng)在Golang-dev group上做了長(zhǎng)時(shí)間的調(diào)研。最終Russ Cox在?Keith Rarick?的proposal的基礎(chǔ)上做了改良,形成了Go 1.5中的vendor:
- 不rewrite gopath
- go tool來(lái)解決
- go get兼容
- 可reproduce building process
并給出了vendor機(jī)制的”4行”詮釋:
If there is a source directory d/vendor, then, when compiling a source file within the subtree rooted at d, import “p” is interpreted as import “d/vendor/p” if that exists.
When there are multiple possible resolutions,the most specific (longest) path wins.
The short form must always be used: no import path can contain “/vendor/” explicitly.
Import comments are ignored in vendored packages.
總結(jié)解釋起來(lái):
- vendor是一個(gè)特殊的目錄,在應(yīng)用的源碼目錄下,go doc工具會(huì)忽略它。
- vendor機(jī)制支持嵌套vendor,vendor中的第三方包中也可以包含vendor目錄。
- 若不同層次的vendor下存在相同的package,編譯查找路徑優(yōu)先搜索當(dāng)前pakcage下的vendor是否存在,若沒有再向parent pacakge下的vendor搜索(x/y/z作為parentpath輸入,搜索路徑:x/y/z/vendor/path->x/y/vendor/path->x/vendor/path->vendor/path)
- 在使用時(shí)不用理會(huì)vendor這個(gè)路徑的存在,該怎么import包就怎么import,不要出現(xiàn)import “d/vendor/p”的情況。vendor是由go tool隱式處理的。
- 不會(huì)校驗(yàn)vendor中package的import path是否與canonical import路徑是否一致了。
vendor機(jī)制看似像node.js的node_modules,支持嵌套vendor,若一個(gè)工程中在著兩個(gè)版本的相的包,可以放在不同的層次的vendor下:
- 優(yōu)點(diǎn):可能解決不同的版本依賴沖突問(wèn)題,不同的層次的vendor存放在不同的vendor。
- 缺點(diǎn):由于go的package是以路徑組織的,在編譯時(shí),不同層次的vendor中相同的包會(huì)編譯兩次,鏈接兩份,程序文件變大,運(yùn)行期是執(zhí)行不同的代碼邏輯。會(huì)導(dǎo)致一些問(wèn)題,如果在package init中全局初始化,可能重復(fù)初化出問(wèn)題,也可能初化為不同的變量(內(nèi)存中不同),無(wú)法共享獲取。像之前我們遇到gprc類似的問(wèn)題就是不同層次的相同package重復(fù)init導(dǎo)致的,見社區(qū)反饋?。
所以Russ Cox期望大家良好設(shè)計(jì)工程布局,作為lib的包?不攜帶vendor更佳 ,一個(gè)project內(nèi)的所有vendor都集中在頂層vendor里面。
后續(xù)
Go的包依賴問(wèn)題依舊困擾著開發(fā)人員,嵌套vendor可以一定程度解決多版本的依賴沖突問(wèn)題,但也引入多份編譯導(dǎo)致的問(wèn)題。目前社區(qū)也在一直討論如何更好的解決,將進(jìn)入下一個(gè)改進(jìn)周期。這次將在Peter Bourgon的主持下正式啟動(dòng):?go packaging proposal process?,當(dāng)前1.8版本特性已凍結(jié),不知這個(gè)改進(jìn)是否會(huì)引入到1.9版本中。
參考:
[1]?理解Go 1.5 vendor
[2]?Golang的包管理之道
Go 語(yǔ)言本身提供的包管理機(jī)制
在 Go 語(yǔ)言中,我們可以使用go get命令安裝遠(yuǎn)程倉(cāng)庫(kù)中托管的代碼,不同于 Ruby Gem、pypi 等集中式的包管理機(jī)制, Go 語(yǔ)言的包管理系統(tǒng)是去中心化的。簡(jiǎn)單來(lái)講,go get命令支持任何一個(gè)位置托管的 Git 或 Mercurial 的倉(cāng)庫(kù),無(wú)論是 Github 還是 Google Code 上的包,都可以通過(guò)這個(gè)命令安裝。
我們知道,在 Go 語(yǔ)言中的import語(yǔ)句對(duì)于已經(jīng)使用go get安裝到本地的包,依然要使用其去絕對(duì)路徑引入。 比如對(duì)于從 Github 上安裝的?goji,其在 Github 上的路徑 URL 是https://github.com/zenazn/goji,因此在import它的時(shí)候需要使用下面的代碼:
| 1 | import "github.com/zenazn/goji" |
正因?yàn)槿绱?#xff0c;Go 語(yǔ)言可以通過(guò)直接分析代碼中的import語(yǔ)句來(lái)查詢依賴關(guān)系。?go get命令在執(zhí)行時(shí),就會(huì)自動(dòng)解析import來(lái)安裝所有的依賴。
除了go get,Go 語(yǔ)言還提供了一個(gè) Workspace 的機(jī)制,這個(gè)機(jī)制也是很容易讓人困惑的設(shè)計(jì)。簡(jiǎn)單來(lái)說(shuō)就是通過(guò)設(shè)定?GOPATH環(huán)境變量,指定除了GOROOT所指定的目錄之外,Go 代碼所在的位置(也就是 Workspace 的位置)。 一般來(lái)說(shuō),GOPATH目錄下會(huì)包含pkg、src和bin三個(gè)子目錄,這三個(gè)目錄各有用處。
- bin?目錄用來(lái)放置編譯好的可執(zhí)行文件,為了使得這里的可執(zhí)行文件可以方便的運(yùn)行, 在 shell 中設(shè)置PATH變量。
- src?目錄用來(lái)放置代碼源文件,在進(jìn)行import時(shí),是使用這個(gè)位置作為根目錄的。自己編寫的代碼也應(yīng)該放在這下面。
- pkg?用來(lái)放置安裝的包的鏈接對(duì)象(Object)的。這個(gè)概念有點(diǎn)類似于鏈接庫(kù),Go 會(huì)將編譯出的可連接庫(kù)放在這里, 方便編譯時(shí)鏈接。不同的系統(tǒng)和處理器架構(gòu)的對(duì)象會(huì)在pkg存放在不同的文件夾中。
我的GOPATH目錄樹如下所示:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | ├── bin ├── pkg │?? └── darwin_amd64 │?? └── github.com │?? └── zenazn │? ?? └── goji └── src ├── code.google.com │?? └── p │?? └── go.crypto └── github.com ?? └── zenazn ?? └── goji |
一般來(lái)說(shuō),你自己的代碼不應(yīng)該直接放置在src目錄下,而應(yīng)該為其建立對(duì)應(yīng)的項(xiàng)目文件夾。?go get也會(huì)把第三方包的源代碼放到這個(gè)目錄下,因此一般推薦設(shè)置兩個(gè)GOPATH,比如:
| 1 | export GOPATH="/usr/local/share/go:$HOME/codes/go" |
這樣第三方包就會(huì)默認(rèn)放置在第一個(gè)路徑中,而你可以在第二個(gè)路徑下編寫自己的代碼。 雖然 Go 語(yǔ)言本身已經(jīng)提供了相當(dāng)強(qiáng)大的包管理方式了,但是仍然有一些不足:
因此我們還需要一些第三方的工具來(lái)彌補(bǔ)這些缺陷。
第三方的管理工具
GOPATH 管理和包管理
由于存在GOPATH的機(jī)制,我們可以使用多個(gè)GOPATH來(lái)實(shí)現(xiàn)項(xiàng)目隔離的方法。 譬如,對(duì)于每個(gè)項(xiàng)目,都分配一個(gè)不同的路徑作為GOPATH。 可以實(shí)現(xiàn)這樣的目的的工具有g(shù)vp等。
對(duì)于 gvp 來(lái)說(shuō),想要針對(duì)當(dāng)前目錄建立一個(gè)GOPATH,只需要執(zhí)行g(shù)vp init即可。 gvp 會(huì)在當(dāng)前項(xiàng)目的目錄下新建一個(gè)隱藏的文件夾作為GOPATH指向的位置。 切換環(huán)境時(shí)使用下面兩個(gè)命令來(lái)修改環(huán)境變量。這種做法跟 Python 中的virtualenv比較類似。
| 1 2 | source gvp in # 進(jìn)入當(dāng)前目錄對(duì)應(yīng)的 GOPATH 環(huán)境 source gvp out # 登出當(dāng)前目錄對(duì)應(yīng)的 GOPATH 環(huán)境 |
至于對(duì)依賴包更版本更細(xì)致的管理,可以配合的工具還有?gpm。?gpm有點(diǎn)類似于 Python 中的pip工具。他可以生成一個(gè)名為?Godeps?的文件, 其中記錄了每個(gè)依賴包的 URL 以及使用的版本(hash tag)。 之前的一篇文章提到?gpm只能管理來(lái)自 Github 的依賴,不過(guò)當(dāng)前的版本已經(jīng)支持了非 Git 方式托管的依賴包了。
基于同樣原理管理依賴包版本的工具還有Godep。 這個(gè)工具在 Github 上具有相當(dāng)高的關(guān)注度。它所生成的Godeps文件采用 JSON 格式儲(chǔ)存, 是一個(gè)跟 Node.js 中?NPM?相仿的工具。
總體來(lái)說(shuō)以上幾個(gè)工具已經(jīng)可以解決隔離項(xiàng)目環(huán)境和控制依賴包版本的問(wèn)題了。但是使用上還不算方便, 為了能在我們 cd 到某個(gè)目錄時(shí)自動(dòng)的切換環(huán)境變量,我們可能還需要在 shell 做一些配置使其在cd到項(xiàng)目目錄下時(shí)自動(dòng)切換環(huán)境變量。
這方面做的比較好的一個(gè)選擇是?Go Manager(gom), 它生成的Gomfile格式上幾乎跟 Ruby Gem 一樣。gom 可能是這些工具當(dāng)中使用最方便的一個(gè), 只要使用gom build命令代替原來(lái)的go build命令進(jìn)行編譯,你基本不需要配置 Shell 或者和環(huán)境變量打交道。
Go 語(yǔ)言版本管理
對(duì)于 Go 語(yǔ)言,一般來(lái)說(shuō)并沒有使多個(gè)語(yǔ)言版本并存的需求。Go 語(yǔ)言現(xiàn)在還沒有經(jīng)歷過(guò)類似 Python 2.x 到 3.x 或者 Ruby 1.x 到 2.x 這樣破壞性的版本升級(jí)。舊的代碼在新的語(yǔ)言版本當(dāng)中一般是能夠正確運(yùn)行的。 不過(guò)若遇到非要并存多個(gè)版本的時(shí)候,gvm就是一個(gè)不錯(cuò)的選擇。
gvm 的使用跟?rvm?比較類似。
| 1 2 | gvm install go1 # 安裝 go1 版本 gvm use go1 # 修改環(huán)境變量使用 go1 版本的 Go |
總結(jié)
是否有必要使用多個(gè) Workspace 仍然具有爭(zhēng)議,譬如這個(gè) StackOverflow 上的相關(guān)問(wèn)答中, 就有人提出只使用一個(gè) Workspace 就可以應(yīng)付大多數(shù)情況了。
在研究相關(guān)問(wèn)題的時(shí)候,我發(fā)現(xiàn)很多 Go 語(yǔ)言的用戶都還帶著原來(lái)編程語(yǔ)言的思維, 這點(diǎn)從上面介紹的多個(gè)工具的特點(diǎn)當(dāng)中就可以很容易看出來(lái):gvp和gpm就是典型的 Python 的包管理模式,?gvp對(duì)應(yīng)著virtualenv,gpm對(duì)應(yīng)著pip;如果你之前是 Node.js 和 NPM 的用戶, 那么GoDeps肯定會(huì)讓你有種熟悉的感覺;更不用說(shuō)最后介紹的gom了,它從名稱到文件格式都在模仿 Ruby Gem。
不同編程背景的開發(fā)者來(lái)到 Go 語(yǔ)言之后各自帶來(lái)了自己的依賴包管理方式,而且形成了各自的社區(qū)。 這種現(xiàn)象雖然使得各自圈子的開發(fā)者免去了選擇恐懼癥,但是造成的解決方案分裂和互不兼容的情況也需要正視。 這時(shí)我們不禁要問(wèn),Go 自己的解決方式應(yīng)該是什么樣的?Go 語(yǔ)言為何沒有一個(gè)官方標(biāo)準(zhǔn)的解決方案呢?
從Go FAQ的一段文字當(dāng)中我們可以得到部分答案:
Versioning is a source of significant complexity, especially in large code bases, and we are unaware of any approach that works well at scale in a large enough variety of situations to be appropriate to force on all Go users. (依賴包的版本管理是一個(gè)非常復(fù)雜的問(wèn)題,特別是在代碼量比較大的時(shí)候。 我們一直沒有找到任何一種方式能夠在各種情形下都能良好工作, 因此也沒有一種方式足夠好到應(yīng)該強(qiáng)迫所有的 Go 用戶使用它)
因此現(xiàn)階段來(lái)看,對(duì)于 Go 語(yǔ)言的包管理解決方案,我們也就只能“仁者見仁,智者見智”了。
最后,對(duì)于想要了解 Go 語(yǔ)言的包管理以及更多可用的工具的讀者,這里再推薦兩篇相關(guān)的文章:?Go Package Management?和?A Journey in Golang Package Manager
總結(jié)
- 上一篇: 深入浅出Go Runtime
- 下一篇: ✿ iBm T60 水货入手了 满意 2