golang快速入門[1]-go語言導論linux
《莊子》‘逍遙遊’有云:且夫水之積也不厚,則其負大舟也無力。覆杯水於坳堂之上,則芥爲之舟;置杯焉則膠,水淺而舟大也。
咱們今天要介紹的就是北冥神功—go module絕技,以吸取他人內力爲己所用。並且別人的內力愈強 吸力愈大。極天下代碼於一身,好不快活。
在上文中,咱們介紹了gopath
的含義、功能、優劣、以及如何經過GOPATH來組織項目
在本文中,咱們將介紹go module
的原理和用法以試圖可以回答下面的幾個問題
go module 是什麼?
go module爲何須要?
go module的基本使用方法是什麼?
go module如何管理版本與依賴?
go module如何解決依賴的衝突問題?
go module 環境變量的配置與使用方式?
如何搭建私有 module鏡像?
在go module
以前,有一些問題長期困擾go語言的開發人員
可否將go工程代碼脫離gopath
以外
可否處理版本依賴問題而且自動選擇最兼容的依賴版本
可否使用go工具本地管理依賴項,自定義依賴項
go1.11開始支持,go1.13全面支持的go modules
正是爲了解決上面的問題誕生的,下面咱們詳細介紹go module
企圖解決的問題
在介紹gopath
時,咱們介紹了若是導入爲
import "github.com/gobuffalo/buffalo"
實際引用的是$GOPATH/src/github.com/gobuffalo/buffalo
文件中的代碼。
也就是說,在gopath
中 ,導入路徑與項目在文件系統中的目錄結構和名稱必須是匹配的。
那麼可否import
路徑爲github.com/gobuffalo/buffalo
,可是項目實際的路徑倒是在另外一個任意的文件目錄中?(例如/users/gobuffalo/buffalo
).答案是確定的,go module
經過在一個特殊的叫作go.mod
的文件中指定模塊名來解決這一問題。
## go.mod
01 module github.com/gobuffalo/buffalo
02
...
06
在go.mod文件的第一行指定了模塊名,模塊名錶示開發人員能夠用此來引用當前代碼倉庫中任何package
的路徑名,以此來替代$gopath
的路徑。從而,代碼倉庫在任何位置都已經沒有關係,由於Go工具可使用模塊文件的位置和模塊名來解析代碼倉庫中的任何內部import
。
對於任何版本控制(VCS)工具,咱們都能在任何代碼提交點打上"tag"標記,以下所示:
使用VCS工具,開發人員能夠經過引用特定標籤將軟件包的任何特定版本克隆到本地。
當咱們引用一個第三方包時,可能並不老是但願應用項目最新的代碼,而是某一個特定與當前項目兼容的代碼。對於某一個項目來講,可能並無意識到有人在使用他們的代碼,或者某種緣由進行了巨大的不兼容更新。
咱們但願可以指明須要使用的第三方包的版本,而且go工具可以方便下載、管理
更棘手的是,一個第三方包A可能引用了其餘的第三方包B,所以還必須把第三方包A的所有依賴下載
如何查找並把全部的依賴包下載下來?
某一個包下載失敗應該怎麼辦?
全部項目之間如何進行依賴的傳導?
如何選擇一個最兼容的包?
如何解決包的衝突?
若是但願在項目中同時引用第三方包的二個不一樣版本,須要如何處理?
所以,只經過gopath
維護單一的master包的方式是遠遠不夠的,由於依賴包的最新代碼不必定與項目兼容。儘管go社區已經針對以上問題提供了一些解決方案(例如dep,godep,glide等)可是go官方的go moudle
提供了一種集成解決方案,經過在文件中維護直接和間接依賴項的版本列表來解決這一問題。經過將一個特定版本的依賴項看作是捆綁的不可變的依賴項,就叫作一個模塊(moudle)
爲了加快構建程序的速度並快速切換、獲取項目中依賴項的更新,Go維護了下載到本地計算機上的全部模塊的緩存,緩存目前默認位於$GOPATH/pkg
目錄中。有go的提議但願可以自定義緩存的位置。
所在位置看上去以下所示:
go/
├── bin
├── pkg
├── darwin_amd64
└── mod
└── src
在mod目錄下,咱們可以看到模塊名路徑中的第一部分用做了模塊緩存中的頂級文件夾
~/go/pkg/mod » ls -l jackson@192
drwxr-xr-x 6 jackson staff 192 1 15 20:50 cache
drwxr-xr-x 7 jackson staff 224 2 20 17:50 cloud.google.com
drwxr-xr-x 3 jackson staff 96 2 18 12:03 git.apache.org
drwxr-xr-x 327 jackson staff 10464 2 28 00:02 github.com
drwxr-xr-x 8 jackson staff 256 2 20 17:27 gitlab.followme.com
drwxr-xr-x 6 jackson staff 192 2 19 22:05 go.etcd.io
...
當咱們打開一個實際的模塊,例如github.com/nats-io
,咱們會看到與nats庫有關許多模塊
~/go/pkg/mod » ls -l github.com/nats-io jackson@192
total 0
dr-x------ 24 jackson staff 768 1 17 10:27 gnatsd@v1.4.1
dr-x------ 15 jackson staff 480 2 17 22:22 go-nats-streaming@v0.4.0
dr-x------ 26 jackson staff 832 2 19 22:05 go-nats@v1.7.0
dr-x------ 26 jackson staff 832 1 17 10:27 go-nats@v1.7.2
...
爲了擁有一個乾淨的工做環境,咱們能夠用以下代碼清空緩存區。可是請注意,在正常的工做流程中,是不須要執行以下代碼的。
$ go clean -modcache
咱們從GOPATH
外開始一個新的項目講解,新建一個新建夾以及一個main
文件
$ cd $HOME
$ mkdir mathlib
$ cd mathlib jackson@192
$ touch main.go
接着在當前目錄中,執行以下指令初始化moudle。
~/mathlib » go mod init github.com/dreamerjackson/mathlib
go mod init
指令的功能很簡單,自動生成一個go.mod
文件 後面緊跟的路徑便是自定義的模塊名。習慣上以託管代碼倉庫的URL爲模塊名(代碼將會放置在https://github.com/dreamerjackson/mathlib
下)
go.mod
文件 位於項目的根目錄下,內容以下所示,第一行即爲模塊名。
module github.com/ardanlabs/service
#### 引入第三方模塊
go 1.13
接下來咱們將書寫初始化的代碼片斷
package main
import "github.com/dreamerjackson/mydiv"
func main(){
}
咱們在代碼片斷中導入了爲了講解go moudle
而特意的引入的packagegithub.com/dreamerjackson/mydiv
,其進行簡單的除法操做,同時又引入了另外一個包github.com/pkg/errors
。其代碼以下圖所示:
以下圖所示,在goland中咱們能夠看到導入的package 是紅色的,由於此時在go module的緩存並不能找到此package。
爲了可以將此package下載到本地,咱們可使用go mod tidy
指令
$ go mod tidy
go: finding github.com/dreamerjackson/mydiv latest
go: downloading github.com/dreamerjackson/mydiv v0.0.0-20200305082807-fdd187670161
go: extracting github.com/dreamerjackson/mydiv v0.0.0-20200305082807-fdd187670161
同時咱們在go.mod
中可以看到新增長了一行用於表示咱們引用的依賴關係
module github.com/dreamerjackson/mathlib
go 1.13
require github.com/dreamerjackson/mydiv v0.0.0-20200305082807-fdd187670161
注意在這裏間接的依賴(即github.com/dreamerjackson/mydiv
依賴的github.com/pkg/errors
)並無也沒有必要在go.mod
文件展現出來,而是出如今了一個自動生成的新的文件go.sum
中.
## go.sum
github.com/dreamerjackson/mydiv v0.0.0-20200305082807-fdd187670161 h1:QR1fJ05yjzJ0qv1gcUS+gAe5Q3UU5Y0le6TIb2pcJpQ=
github.com/dreamerjackson/mydiv v0.0.0-20200305082807-fdd187670161/go.mod h1:h70Xf3RkhKSNbUF8W3htLNJskYJSITf6AdEGK22QksQ=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
接着就能夠愉快的調用咱們的代碼了
package main
import (
"fmt"
"github.com/dreamerjackson/mydiv"
)
func main(){
res,_ :=mydiv.Div(4,2)
fmt.Println(res)
}
運行go run
命令後,即會爲咱們輸出除法結果2
假設咱們依賴的第三方包出現了更新怎麼辦?若是將依賴代碼更新到最新的版本呢?
有多種方式能夠實現依賴模塊的更新,在go.mod
文件中修改版本號爲:
require github.com/dreamerjackson/mydiv latest
或者
require github.com/dreamerjackson/mydiv master
獲取複製commitId 到最後
require github.com/dreamerjackson/mydiv c9a7ffa8112626ba6c85619d7fd98122dd49f850
還有一種辦法是在終端當前項目中,運行go get
go get github.com/dreamerjackson/mydiv
上述幾種方式在保存文件後,再次運行go mod tidy
即會進行更新
此時若是咱們再次打開go.sum
文件會發現,go.sum
中不只僅存儲了直接和間接的依賴,還會存儲過去的版本信息。
github.com/dreamerjackson/mydiv v0.0.0-20200305082807-fdd187670161 h1:QR1fJ05yjzJ0qv1gcUS+gAe5Q3UU5Y0le6TIb2pcJpQ=
github.com/dreamerjackson/mydiv v0.0.0-20200305082807-fdd187670161/go.mod h1:h70Xf3RkhKSNbUF8W3htLNJskYJSITf6AdEGK22QksQ=
github.com/dreamerjackson/mydiv v0.0.0-20200305090126-c9a7ffa81126/go.mod h1:h70Xf3RkhKSNbUF8W3htLNJskYJSITf6AdEGK22QksQ=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
當咱們不想在使用此第三方包時,能夠直接在代碼中刪除無用的代碼,接着執行
$ go mod tidy
會發現go.mod
與go.sum
一切又都空空如也~
每一個依賴管理解決方案都必須解決選擇依賴版本的問題,當今存在的許多版本選擇算法都試圖識別任何依賴的「最新最大」版本。若是您認爲語義版本控制被正確應用而且將遵照約定,那麼這是有道理的。在這些狀況下,依賴項的「最新最大」版本應該是最穩定和安全的版本,而且應與較早版本具備向後兼容性。
Go決定採用其餘方法,Russ Cox花費了大量時間和精力撰寫和談論 Go團隊的版本選擇方法,即最小版本選擇(Minimal Version Selection,MVS)。從本質上講,Go團隊相信MVS能夠爲Go程序提供最佳的機會,以實現兼容性和可重複性。我建議閱讀這篇文章,以瞭解Go團隊爲何相信這一點。
go最小版本選擇指的是選擇項目中最合適的最小版本。並非說MVS不能選擇最新的版本,而是若是項目中任何依賴不須要最新的版本,則不須要它。
舉一個簡單的例子,假設如今項目github.com/dreamerjackson/mydiv
的最新版本爲v1.0.2
,可經過下面指令查看全部
> go list -m -versions github.com/dreamerjackson/mydiv
github.com/dreamerjackson/mydiv v1.0.0 v1.0.1 v1.0.2 v1.0.3
假設如今有兩個模塊A、B,都依賴模塊D。其中
A -> D v1.0.1,
B -> D v1.0.2
若是咱們的當前項目只依賴A,這個時候go module
會如何選擇呢?像dep這樣的依賴工具將選擇v1.0.3,即最新的語義版本控制。可是在go module
中,最小版本選擇原理將遵循A項目聲明的版本,即v1.0.1
若是隨後當前項目又引入了模塊B的新代碼怎麼辦?將模塊B導入項目後,Go會將項目的模塊D版本從v1.0.1升到v1.0.2。爲模塊D的全部依賴項(模塊A和B)選擇模塊D的「最小」版本,該版本當前處於所需版本集(v1.0.1和v.1.0.2)中
最後,若是刪除剛剛爲模塊B添加的代碼,會發生什麼?Go會將項目鎖定到模塊D的版本v1.0.2中。降級到版本v1.0.1將是一個更大的更改,而Go知道版本v1.0.1能夠正常運行而且穩定,所以版本v1.0.2仍然是「最新版本」。
爲了驗證最小版本選擇原理,做者嘔心瀝血設計了一個簡單的示例。
以項目github.com/dreamerjackson/mydiv
爲例,讀者能夠將其看作上節中的模塊D
,其v1.0.1
與v1.0.2
版本的代碼以下,只是簡單的改變了錯誤返回的字符串。
## v1.0.1
package mydiv
import "github.com/pkg/errors"
func Div(a int,b int) (int,error){
if b==0{
return 0,errors.Errorf("new error b can't = 0")
}
return a/b,nil
}
## v1.0.2
package mydiv
import "github.com/pkg/errors"
func Div(a int,b int) (int,error){
if b==0{
return 0,errors.Errorf("new error b can't = 0")
}
return a/b,nil
}
接着模塊B
即github.com/dreamerjackson/minidiv
引用了模塊D即github.com/dreamerjackson/mydiv
v1.0.1版本
## 模塊B
package div
import (
"github.com/dreamerjackson/mydiv"
)
func Div(a int,b int) (int,error){
return mydiv.Div(a,b)
}
最後當前的項目,咱們將其稱爲模塊Now
直接依賴了模塊D v1.0.2,同時依賴了模塊B
當前代碼以下:
package main
import (
"fmt"
div "github.com/dreamerjackson/minidiv"
"github.com/dreamerjackson/mydiv"
)
func main(){
_,err1:= mydiv.Div(4,0)
_,err2 := div.Div(4,0)
fmt.Println(err1,err2)
}
當前的依賴關係以下:
當前模塊 --> 模塊D v1.0.2
當前模塊 --> 模塊B --> 模塊D v1.0.1
所以咱們將驗證,是否和咱們所料,當前項目選擇了模塊D v1.0.2 呢?
驗證方式有兩種:第一種爲直接運行,查看項目採用了哪個版本的代碼
$ go run main.go
v1.0.2 b can't = 0 v1.0.2 b can't = 0
如上所示,輸出的結果所有是咱們在模塊D v1.0.2中定義的代碼!
第二種方式是使用go list
指令
~/mathlib » go list -m all | grep mydiv
github.com/dreamerjackson/mydiv v1.0.2
咱們還能夠經過使用go mod mhy
z指令,查看在哪裏引用了包github.com/dreamerjackson/mydiv
~/mathlib » go mod why github.com/dreamerjackson/mydiv
# github.com/dreamerjackson/mydiv
github.com/dreamerjackson/mathlib
github.com/dreamerjackson/mydiv
咱們可使用go list -m -u all
指令查看直接和間接模塊的當前和最新版本
~/mathlib » go list -m -u all | column -t jackson@192
go: finding github.com/dreamerjackson/minidiv latest
github.com/dreamerjackson/mathlib
github.com/dreamerjackson/minidiv v0.0.0-20200305104752-fcd15cf402bb
github.com/dreamerjackson/mydiv v1.0.2 [v1.0.3]
github.com/pkg/errors v0.9.1
如上所示,咱們能夠看到github.com/dreamerjackson/mydiv
的當前版本爲v1.0.2
,可是最新的版本爲v1.0.3
獲取直接和間接模塊可使用go get
指令。其中有很多的參數。
下面命令以最小版本原則
更新全部的直接和間接模塊
go get -t -d -v ./...
-t
考慮構建測試所需的模塊
-d
下載每一個模塊的源代碼
-v
提供詳細輸出
./…
在整個源代碼樹中執行這些操做,而且僅更新所需的依賴項
注意,除非你瞭解項目的全部細節,不然慎用所有的最大最新版本的更新
若是go get中使用-u
參數會用最大最新版本
原則更新全部的直接和間接模塊
~/mathlib » go get -u -t -d -v ./... jackson@192
go: finding github.com/dreamerjackson/minidiv latest
go: downloading github.com/dreamerjackson/mydiv v1.0.3
go: extracting github.com/dreamerjackson/mydiv v1.0.3
接着咱們能夠再次查看當前引用的版本,咱們會發現模塊github.com/dreamerjackson/mydiv
已經強制更新到了最新的v1.0.3
~/mathlib » go list -m all | grep mydiv jackson@192
github.com/dreamerjackson/mydiv v1.0.3
若是您不滿意所選的模塊和版本,則始終能夠經過刪除go.mod go.sum
模塊文件並再次運行go mod tidy來重置。當項目還不太成熟時這是一種選擇。
$ rm go.*
$ go mod init <module name>
$ go mod tidy
Go模塊引入了一種新的導入路徑語法,即語義導入版本控制。每一個語義版本均採用vMAJOR.MINOR.PATCH的形式。
MAJOR 主版本號,若是有大的版本更新,致使 API 和以前版本不兼容。咱們遇到的就是這個問題。
MINOR 次版本號,當你作了向下兼容的新 feature。
PATCH 修訂版本號,當你作了向下兼容的修復 bug fix。
v 全部版本號都是 v 開頭。
若是兩個版本具備相同的主編號,則預期更高版本(若是您願意,更大版本)將與較早版本(較小版本)向後兼容。可是,若是兩個版本的主要編號不一樣,則它們之間沒有預期的兼容性關係。
所以咱們在上面的實例中能夠看到,go預料到v1.0.3與v1.0.1是兼容的,由於他們有相同的主版本號1
。可是通常咱們將版本升級到了v2.0.0
,即被認爲是出現了重大的更新。
如上圖實例顯示了go對於版本更新的處理。my/thing/v2
標識特定模塊的語義主版本2
。版本1是my/thing
,模塊路徑中沒有明確的版本。可是,當您引入主要版本2或更大版本時,必須在模塊名稱後添加版本,以區別於版本1和其餘主要版本,所以版本2爲my/thing/v2,版本3爲my/thing/v3,依此類推。
假設模塊A引入了模塊B和模塊C,模塊B引入了模塊Dv1.0.0,模塊C引入了模塊Dv2.0.0。則看起來就像是
A --> 模塊B --> 模塊D v1.0.0
A --> 模塊C --> 模塊D v2.0.0
因爲v1 和v2 模塊的路徑不相同,所以他們之間會是互不干擾的兩個模塊。
下面咱們用實例來驗證
首先咱們給mydiv打一個v2.0.0的tag,其代碼以下,簡單修改了錯誤文字v2.0.0 b can't = 0
package mydiv
import "github.com/pkg/errors"
func Div(a int,b int) (int,error){
if b==0{
return 0,errors.Errorf("v2.0.0 b can't = 0")
}
return a/b,nil
}
同時須要修改v2模塊路徑名爲:
module github.com/dreamerjackson/mydiv/v2
接着在mathlib中,代碼以下:
package main
import (
"fmt"
div "github.com/dreamerjackson/minidiv"
mydiv "github.com/dreamerjackson/mydiv/v2"
)
func main(){
_,err1:= mydiv.Div(4,0)
_,err2 := div.Div(4,0)
fmt.Println(err1,err2)
}
如今的依賴路徑能夠表示爲爲:
mathlib --> 直接引用mydiv v2
mathlib --> 直接引用minidiv --> 間接引用mydiv v1
當咱們運行代碼以後,會發現兩段代碼是共存的
v2.0.0 b can't = 0 ::v1.0.1 b can't = 0
接着執行go list
,模塊共存,驗證成功~
~/mathlib(master*) » go list -m all | grep mydiv
github.com/dreamerjackson/mydiv v1.0.1
github.com/dreamerjackson/mydiv/v2 v2.0.1
模塊鏡像於2019年八月推出,是go官方1.13版本的默認系統。模塊鏡像是一個代理服務器,以幫助加快構建本地應用程序所需的模塊的獲取。代理服務器實現了基於REST的API,並根據Go工具的需求進行了設計。
模塊鏡像將會緩存已請求的模塊及其特定版本,從而能夠更快地檢索未來的請求。一旦代碼被獲取並緩存在模塊鏡像中,就能夠將其快速提供給世界各地的用戶。
checksum數據庫也於2019八月推出,是能夠用來防止模塊完整性、有效性的手段。它驗證特定版本的任何給定模塊代碼的正確性,而無論何人什麼時候何地以及是如何獲取的。Google擁有惟一的校驗和數據庫,可是能夠經過私有模塊鏡像對其進行緩存。
有幾個環境變量能夠控制與模塊鏡像和checksum數據庫有關的行爲
GOPROXY:一組指向模塊鏡像的URL,用於獲取模塊。若是您但願Go工具僅直接從VCS地址獲取模塊,則能夠將其設置爲direct
。若是將此設置爲off
,則將不會下載模塊
GOSUMDB:用於驗證給定模塊/版本的代碼的checksum數據庫地址。此地址用於造成一個適當的URL,該URL告訴Go工具在哪裏執行這些checksum校驗和查找。該URL能夠指向Google擁有的checksum數據庫,也能夠指向支持對checksum數據庫進行緩存或代理的本地模塊鏡像。若是您不但願Go工具驗證添加到go.sum文件中的給定模塊/版本的哈希碼,也能夠將其設置爲off,僅在將任何新module添加到go.sum文件之時,才查詢checksum數據庫
GONOPROXY:一組基於URL的模塊路徑,這些模塊不會使用模塊鏡像來獲取,而應直接在VCS地址上獲取。
GONOSUMDB:一組基於URL的模塊路徑,這些模塊的哈希碼不會在checksum數據庫中查找。
GOPRIVATE:一個方便變量,用於將GONOPROXY和GONOSUMDB設置爲相同的默認值
咱們能夠經過go env
來查看到這些默認值
$ go env
GONOPROXY=""
GONOSUMDB=""
GOPRIVATE=""
GOPROXY="https://proxy.golang.org,direct"
GOSUMDB="sum.golang.org"
這些默認值告訴Go工具使用Google模塊鏡像和Google checksum數據庫。若是這些Google服務能夠訪問您所需的全部代碼,則建議使用此配置。若是Google模塊鏡像剛好以410(消失)或404(未找到)響應,則使用direct(這是GOPROXY配置的一部分)將容許Go工具更改路線並直接獲取模塊/版本VCS位置。
例如,若是咱們須要訪問全部代理服務器,例如須要權限的位於gitlab
等地的代碼,咱們可使用export GOPRIVATE=gitlab.XXX.com,gitlab.XXX-XX.com,XXX.io
多個域名用逗號分隔。
Athens是一個私有模塊鏡像,能夠用於搭建私有模塊鏡像。使用私有模塊鏡像的一個緣由是容許緩存公共模塊鏡像沒法訪問的私有模塊。Athens項目提供了一個在Docker Hub
上發佈的Docker
容器,所以不須要特殊的安裝。
docker run -p '3000:3000' gomods/athens:latest
接下來,啓動一個新的終端會話以運行Athens,爲你們演示其用法。啓動Athens服務並經過額外的參數調試日誌(請確保系統已經安裝並啓動了docker)並有科學*上網的環境
$ docker run -p '3000:3000' -e ATHENS_LOG_LEVEL=debug -e GO_ENV=development gomods/athens:latest
INFO[7:11AM]: Exporter not specified. Traces won't be exported
2020-03-06 07:11:30.671249 I | Starting application at port :3000
接着咱們修改GOPROXY參數,指向本地3000
端口,初始化咱們以前的項目,再次執行go mod tidy
$ export GOPROXY="http://localhost:3000,direct"
$ rm go.*
$ go mod init github.com/dreamerjackson/mathlib
$ go mod tidy
在Athens日誌中便可查看對應信息
INFO[7:39AM]: incoming request http-method=GET http-path=/github.com/dreamerjackson/mydiv/@v/list http-status=200
INFO[7:39AM]: incoming request http-method=GET http-path=/github.com/dreamerjackson/minidiv/@v/list http-status=200
INFO[7:39AM]: incoming request http-method=GET http-path=/github.com/dreamerjackson/minidiv/@latest http-status=200
詳細信息,查看參考資料中Athens的官方網站
提供脫離gopath
管理go代碼的優點
提供了代碼捆綁、版本控制、依賴管理的功能
供全球開發人員使用、構建,下載,受權、驗證,獲取,緩存和重用模塊(能夠經過搭建本身的代理服務器來實現這些功能)
能夠驗證模塊(對於任何給定的版本)始終包含徹底相同的代碼,而無論它被構建了多少次,從何處獲取以及由誰獲取
在本文中,使用詳細的實例講解了go module
是什麼,爲何須要,其最佳實踐以及其實現原理。但願讀者在這篇文章以後,可以回答咱們在開頭提出的問題
go module
是什麼?
go module
爲何須要?
go module
的基本使用方法是什麼?
go module
如何管理版本與依賴?
go module
如何解決依賴的衝突問題?
go module
環境變量的配置與使用方式?
如何搭建私有module
鏡像?
see you~
項目連接
做者知乎
blog
Athens
talk youtube
Modules Part 03: Minimal Version Selection
How to Write Go Code
Go module 如何發佈 v2 及以上版本?
The Principles of Versioning in Go