[TOC]
# 簡介
`GO111MODULE`的取值為 off, on, or auto (默認值)。
* off: GOPATH mode,查找vendor和GOPATH目錄
* on:module-aware mode,使用 go module,忽略GOPATH目錄
* auto:如果當前目錄不在$GOPATH**并且**當前目錄(或者父目錄)下有go.mod文件,則使用`GO111MODULE`, 否則仍舊使用 GOPATH mode。
go.mod文件可以通過require,replace和exclude語句使用的精確軟件包集。
* require語句指定的依賴項模塊
* replace語句可以替換依賴項模塊
* exclude語句可以忽略依賴項模塊
注意,go modules 下載的包在`GOPATH/pkg/mod`
執行 go clean -modcache 清除緩存
----
* govendor
* dep
* glide
* godep
這些包管理工具都是基于`GOPATH`或者`vendor`目錄,并不能很好的解決不同版本依賴問題。Modules是在`GOPATH`之外一套新的包管理方式
首先要把go升級到1.11。
升級后,可以設置通過一個環境變量`GO111MODULE`來激活modules:
* GO111MODULE=off,go命令行將不會支持module功能,尋找依賴包的方式將會沿用舊版本那種通過vendor目錄或者GOPATH模式來查找。
* GO111MODULE=on,go命令行會使用modules,而一點也不會去GOPATH目錄下查找。
* GO111MODULE=auto,默認值,go命令行將會根據當前目錄來決定是否啟用module功能。這種情況下可以分為兩種情形:當前目錄在GOPATH/src之外且該目錄包含go.mod文件,或者當前文件在包含go.mod文件的目錄下面。
當module功能啟用時,`GOPATH`在項目構建過程中不再擔當import的角色,但它仍然存儲下載的依賴包,具體位置在`$GOPATH/pkg/mod`。
自從`Go`官方從去年推出 1.11 之后,增加新的依賴管理模塊并且更加易于管理項目中所需要的模塊。模塊是存儲在文件樹中的 Go 包的集合,其根目錄中包含 go.mod 文件。 go.mod 文件定義了模塊的模塊路徑,它也是用于根目錄的導入路徑,以及它的依賴性要求。每個依賴性要求都被寫為模塊路徑和特定語義版本。
從 Go 1.11 開始,Go 允許在 $GOPATH/src 外的任何目錄下使用 go.mod 創建項目。在 $GOPATH/src 中,為了兼容性,Go 命令仍然在舊的 GOPATH 模式下運行。從 Go 1.13 開始,模塊模式將成為默認模式。
本文將介紹使用模塊開發 Go 代碼時出現的一系列常見操作:
* 創建一個新模塊。
* 添加依賴項。
* 升級依賴項。
* 刪除未使用的依賴項。
下面使用的案例都是以`GIN`模塊為例。
在這之前呢,需要先設置一些環境變量:
~~~go
export GO111MODULE=on
export GOPROXY=https://goproxy.io // 設置代理
~~~
# 創建一個新模塊
go mod會下載到`pkg/mod/cache`
你可以在 $GOPATH/src 之外的任何地方創建一個新的目錄。比如:
> mkdir backend && cd backend
然后初始化`go mod init backend`,成功之后你會發現目錄下會生成一個`go.mod`文件.
> $ cat go.mod
>
> 內容如下
>
> module backend
>
> go 1.12
# 添加依賴項
創建一個文件 main.go 然后加入以下代碼,這里直接 import 了 gin 的依賴包。
> vim main.go
~~~go
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/ping", func(c *gin.Context) {
c.JSON(200, gin.H{
"message": "pong",
})
})
r.Run() // listen and serve on 0.0.0.0:8080
}
~~~
go build 之后,會在 go.mod 引入所需要的依賴包。之后再來看看 go.mod 文件的情況。
~~~go
module backend
go 1.12
require (
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3 // indirect
github.com/gin-gonic/gin v1.3.0
github.com/golang/protobuf v1.3.1 // indirect
github.com/mattn/go-isatty v0.0.7 // indirect
github.com/ugorji/go v1.1.4 // indirect
gopkg.in/go-playground/validator.v8 v8.18.2 // indirect
gopkg.in/yaml.v2 v2.2.2 // indirect
~~~
require 就是 gin 框架所需要的所有依賴包 并且在每個依賴包的后面已經表明了版本號
同時多了一個`go.sum`的文件
go.sum不是一個鎖文件,是一個模塊版本內容的校驗值,用來驗證當前緩存的模塊。go.sum包含了直接依賴和間接依賴的包的信息,比go.mod要多一些
# 升級依賴項
首先我們需要查看以下我們使用到的依賴列表
~~~go
> $ go list -m all
// 你會看到所有項目使用的依賴包
backend
github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3
github.com/gin-gonic/gin v1.3.0
github.com/golang/protobuf v1.3.1
github.com/mattn/go-isatty v0.0.7
github.com/ugorji/go v1.1.4
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405
gopkg.in/go-playground/validator.v8 v8.18.2
gopkg.in/yaml.v2 v2.2.2
~~~
因為這里使用的是最新的版本,無法升級,所以這里給出一個回退的例子。將 GIN 框架的版本回退到上個版本。這里需要使用一個命令查看依賴的版本歷史。
~~~go
>$ go list -m -versions github.com/gin-gonic/gin
// 將會列出 Gin 版本歷史
github.com/gin-gonic/gin v1.1.1 v1.1.2 v1.1.3 v1.1.4 v1.3.0
~~~
將版本更新到上個版本,這里只是個演示。
~~~go
>$ go get github.com/gin-gonic/gin@v1.1.4 // 只需要在依賴后面加上 @version 就可以了
>$ go list -m all
// 看到了版本變化
github.com/gin-gonic/gin v1.1.4
~~~
或者可以使用`go mod`來進行版本的切換,這樣就需要兩個步驟了
~~~go
>$ go mod edit -require="github.com/gin-gonic/gin@v1.1.4" // 修改 go.mod 文件
>$ go tidy //下載更新依賴
~~~
`go.tidy`會自動清理掉不需要的依賴項,同時可以將依賴項更新到當前版本
使用起來這是一個很簡單過程,只需要幾個命令,你便可以知道依賴的版本信息,以及自由選擇安裝的版本,一切都變得這么簡單。
# 刪除未使用的依賴項
如果你在項目過程需要移除一些不需要的依賴,可以使用下面的命令來執行:
~~~go
>$ go mod tidy
~~~
更多關于 go mod 的使用命令
~~~go
>$ go mod
The commands are:
download download modules to local cache
edit edit go.mod from tools or scripts
graph print module requirement graph
init initialize new module in current directory
tidy add missing and remove unused modules
vendor make vendored copy of dependencies
verify verify dependencies have expected content
why explain why packages or modules are needed
~~~
# 常用命令
有四種指令:module,require,exclude,replace。
* module:模塊名稱
* require:依賴包列表以及版本
* exclude:禁止依賴包列表(僅在當前模塊為主模塊時生效)
* replace:替換依賴包列表 (僅在當前模塊為主模塊時生效)
可以使用命令`go list -m -u all`來檢查可以升級的package,使用`go get -u need-upgrade-package`升級后會將新的依賴版本更新到go.mod \* 也可以使用`go get -u`升級所有依賴
~~~
go?mod tidy?//拉取缺少的模塊,移除不用的模塊。
~~~
~~~
go?mod download?//下載依賴包
~~~
~~~
go?mod graph?//打印模塊依賴圖
~~~
~~~
go?mod vendor?//將依賴復制到vendor下
~~~
~~~
go?mod?verify?//校驗依賴
~~~
~~~
go?mod why?//解釋為什么需要依賴
~~~
~~~
go?list -m -json all?//依賴詳情
~~~
# 使用replace替換無法直接獲取的package
由于某些已知的原因,并不是所有的package都能成功下載,比如:`golang.org`下的包。
modules 可以通過在 go.mod 文件中使用 replace 指令替換成github上對應的庫,比如:
~~~
replace (
golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a => github.com/golang/crypto v0.0.0-20190313024323-a1f597ede03a
)
復制代碼
~~~
或者
~~~
replace golang.org/x/crypto v0.0.0-20190313024323-a1f597ede03a => github.com/golang/crypto v0
~~~
# idea中配置
goproxy.io 谷歌官方的代理地址,當然還有很多國內優秀的第三方代理。
你也可以在 Goland編輯器中設置
# 主要版本升級
上面版本規則說了,版本 0 和 1,即大版本更新,最好需要有不同的依賴路徑,如:v1.0.0 和 v2.0.0 是有不同的依賴路徑,那么用 go modules 怎么實現呢,我們可以通過修改 go.mod 文件第一行添加新路徑:
~~~
$ cd testmod
$ echo 'module github.com/objcoding/testmod/v2' >> go.mod
~~~
然后我們修改 testmod 函數 Hi():
~~~
$ cd testmod
$ echo 'package testmod
import (
"fmt"
)
func SayHello(name, str string) string {
return fmt.Sprintf("你好, %s, %s", name, str)
}' >> testmod.go
~~~
這時,SayHello() 方法將不兼容 v1 版本,我們需要新建一個 v2.0.0 版本,還是老樣子,我們最好在 v2.0.0 版本新建一條 v2 分分支,將 v2.0.0 版本的代碼寫到這條分支中(這只是一個規范,實際上你將代碼也寫到任何分支中都行,Go并沒有這個規范):
~~~
$ git add *
$ git checkout -b v2
$ git commit testmod.go -m "v2.0.0"
$ git tag v2.0.0
$ git push --tags origin v2
~~~
這時候 testmod 的版本已經更新到 v2.0.0 版本了,該版本并不兼容以前的版本,但是目前項目依然只能獲取到 v1.0.1 的依賴版本,因為我們 testmod 的 module 路徑已經加上 v2 了,因此并不會出現沖突的問題,那么如果我們需要使用 v2.0.0 版本呢?我們只需要在項目中更改一下 import 路徑:
~~~
package main
import (
"fmt"
"github.com/objcoding/testmod/v2"
)
func main() {
fmt.Println(testmod.SayHello("張乘輝", "最近過得怎樣"))
}
~~~
執行:
~~~
go mod tidy
~~~
這時我們把 testmod 依賴版本號更新到了 v2.0.0 版本了,雖然是此時的 import 路徑是以 “v2” 結尾,但是 Go 很人性化,我們依然可以使用 testmod 來使用。
Go 團隊表示,在 Go 1.12 之前,這個特性都將會處于實驗性階段,Go 團隊會努力保持兼容性。一旦模塊穩定之后,對 GOPATH 的支持將會被移除掉
- 基礎
- 簡介
- 主要特征
- 變量和常量
- 編碼轉換
- 數組
- byte與rune
- big
- sort接口
- 和mysql類型對應
- 函數
- 閉包
- 工作區
- 復合類型
- 指針
- 切片
- map
- 結構體
- sync.Map
- 隨機數
- 面向對象
- 匿名組合
- 方法
- 接口
- 權限
- 類型查詢
- 異常處理
- error
- panic
- recover
- 自定義錯誤
- 字符串處理
- 正則表達式
- json
- 文件操作
- os
- 文件讀寫
- 目錄
- bufio
- ioutil
- gob
- 棧幀的內存布局
- shell
- 時間處理
- time詳情
- time使用
- new和make的區別
- container
- list
- heap
- ring
- 測試
- 單元測試
- Mock依賴
- delve
- 命令
- TestMain
- path和filepath包
- log日志
- 反射
- 詳解
- plugin包
- 信號
- goto
- 協程
- 簡介
- 創建
- 協程退出
- runtime
- channel
- select
- 死鎖
- 互斥鎖
- 讀寫鎖
- 條件變量
- 嵌套
- 計算單個協程占用內存
- 執行規則
- 原子操作
- WaitGroup
- 定時器
- 對象池
- sync.once
- 網絡編程
- 分層模型
- socket
- tcp
- udp
- 服務端
- 客戶端
- 并發服務器
- Http
- 簡介
- http服務器
- http客戶端
- 爬蟲
- 平滑重啟
- context
- httptest
- 優雅中止
- web服務平滑重啟
- beego
- 安裝
- 路由器
- orm
- 單表增刪改查
- 多級表
- orm使用
- 高級查詢
- 關系查詢
- SQL查詢
- 元數據二次定義
- 控制器
- 參數解析
- 過濾器
- 數據輸出
- 表單數據驗證
- 錯誤處理
- 日志
- 模塊
- cache
- task
- 調試模塊
- config
- 部署
- 一些包
- gjson
- goredis
- collection
- sjson
- redigo
- aliyunoss
- 密碼
- 對稱加密
- 非對稱加密
- 單向散列函數
- 消息認證
- 數字簽名
- mysql優化
- 常見錯誤
- go run的錯誤
- 新手常見錯誤
- 中級錯誤
- 高級錯誤
- 常用工具
- 協程-泄露
- go env
- gometalinter代碼檢查
- go build
- go clean
- go test
- 包管理器
- go mod
- gopm
- go fmt
- pprof
- 提高編譯
- go get
- 代理
- 其他的知識
- go內存對齊
- 細節總結
- nginx路由匹配
- 一些博客
- redis為什么快
- cpu高速緩存
- 常用命令
- Go 永久阻塞的方法
- 常用技巧
- 密碼加密解密
- for 循環迭代變量
- 備注
- 垃圾回收
- 協程和纖程
- tar-gz
- 紅包算法
- 解決golang.org/x 下載失敗
- 逃逸分析
- docker
- 鏡像
- 容器
- 數據卷
- 網絡管理
- 網絡模式
- dockerfile
- docker-composer
- 微服務
- protoBuf
- GRPC
- tls
- consul
- micro
- crontab
- shell調用
- gorhill/cronexpr
- raft
- go操作etcd
- mongodb