Go Modules 是 Go 语言的代码依赖管理工具。类似于 PHP 中的 Composer、Node.js 中的 npm 。
Go Modules 由官方维护。自 Go 版本 1.14 开始,官方鼓励所有用户迁移到 Go Modules 以进行依赖项管理。
为什么使用Go Modules
1、解决 GOPATH 的问题
在 GOPATH/src` 下,抛弃 $GOPATH 的好处,是你能在任意地方创建的 Go 项目。
2、进行版本管理
使用
1. 初始化
新项目,我们可以使用 go mod init
初始化生成 go.mod
文件:
$ go mod init
2. Go Proxy
因国内访问外网受限,一般我们都会配合 Go Proxy 使用,以防止使用 go get
获取源码包时花费时间过长或无法下载:
$ go env -w GOPROXY=https://goproxy.cn
知识点: 我们使用
go env -w
来修改 Go 相关的环境变量。
Go Proxy 设置完成后即可放心使用 go get
来下载依赖了,作为测试,我们下载 HttpRouter :
$ go get github.com/julienschmidt/httprouter
使用 Proxy 的情况下一般很快就能下载完成。
安装 package 的原则是先拉最新的 release tag,若无 tag 则拉最新的 commit。
3. go.mod
每一次的 go get
都会同时修改 go.mod
和 go.sum
文件。
查看go.mode
module github.com/junetalk/goblog
go 1.17
require github.com/gorilla/mux v1.8.0
几个参数:
- module:我们的 goblog 在 Go Module 里也算是一个 Module ;
- go:指定了版本要求,最低 1.17
- require:是项目所需依赖
4. go.sum
go.sum
文件保存着依赖包的版本和哈希值:
go.sumgithub.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
go.sum
里不仅会保存直接依赖包的哈希值,间接依赖包的哈希值也会被保存。
接下来下载 gin
$ go get github.com/gin-gonic/gin
下载成功后打开 go.sum
,会发现里面的内容远远多于 go.mod
。这是因为 gin 有很多依赖包,而这些依赖包也会有自己的依赖。
每个模块路径有如下两种哈希:
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
前者为 Go Modules 打包整个模块包文件 zip 后再进行 hash 值,而后者为针对 go.mod 的 hash 值。
5.indirect
查看go.mod
中,可以看到 require
区块里有 // indirect
字样:
module github.com/junetalk/goblog
go 1.17
require (
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/gin-gonic/gin v1.7.4 // indirect
github.com/go-playground/locales v0.13.0 // indirect
github.com/go-playground/universal-translator v0.17.0 // indirect
github.com/go-playground/validator/v10 v10.4.1 // indirect
github.com/golang/protobuf v1.3.3 // indirect
github.com/gorilla/mux v1.8.0 // indirect
github.com/json-iterator/go v1.1.9 // indirect
github.com/leodido/go-urn v1.2.0 // indirect
github.com/mattn/go-isatty v0.0.12 // indirect
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 // indirect
github.com/ugorji/go/codec v1.1.7 // indirect
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 // indirect
golang.org/x/sys v0.0.0-20200116001909-b77594299b42 // indirect
gopkg.in/yaml.v2 v2.2.8 // indirect
)
此标志标明这个依赖包还未被使用,如果你在代码的某个地方 import
到的话,VSCode 的 Go 插件就会自动将这个标志去除。
6. go mod tidy 命令
此命令做整理依赖使用,执行时会把未使用的 module 移除掉,我们试试:
$ go mod tidy
再次查看 go.mod
和 go.sum
文件,会发现我们上面测试引入的两个包,因未使用,皆被移除。
7. 源码包的存放位置
默认源码包存放于 $GOPATH/pkg/mod
$ ll $GOPATH/pkg/mod
drwxr-xr-x 5 junetalk staff 160B 9 1 18:53 cache
drwxr-xr-x 23 junetalk staff 736B 9 2 15:05 github.com
drwxr-xr-x 3 junetalk staff 96B 9 1 17:32 golang.org
drwxr-xr-x 3 junetalk staff 96B 9 2 15:05 gopkg.in
drwxr-xr-x 3 junetalk staff 96B 9 1 18:53 honnef.co
drwxr-xr-x 4 junetalk staff 128B 9 1 18:53 mvdan.cc
8. 清空 Go Modules 缓存
使用以下命令可以清空本地下载的 Go Modules 缓存:
$ go clean -modcache
9. 下载依赖
默认情况下,当 go run
和 go build
命令执行时,Go 会基于自动 go.mod
文件自动拉取依赖。
Go Module 也提供了一个命令用以下载项目所需依赖:
$ go mod download
10. 所有 Go Modules 命令
以下是完整的命令列表,有些不常用的篇幅原因我们不做讲解:
命令 | 作用 |
---|---|
go mod init | 生成 go.mod 文件 |
go mod download | 下载 go.mod 文件中指明的所有依赖 |
go mod tidy | 整理现有的依赖 |
go mod graph | 查看现有的依赖结构 |
go mod edit | 编辑 go.mod 文件 |
go mod vendor | 导出项目所有的依赖到 vendor 目录 |
go mod verify | 校验一个模块是否被篡改过 |
go mod why | 查看为什么需要依赖某模块 |
11. 相关环境变量
1). GO111MODULE
此变量为 Go modules 的开关,此值有以下几个可能:
- auto:项目包含了 go.mod 文件的话启用 Go modules,目前在 Go1.11 至 Go1.15 中仍然是默认值。
- on:启用 Go modules,推荐设置,将会是未来版本中的默认值。
- off:禁用 Go modules,不推荐设置。
因是在 Go1.11 版本添加,故命名为 GO111MODULE。
未来 GO111MODULE 会先调整为默认值为 on(曾经在 Go1.13 想想改为 on,并且已经合并了 PR,但最后因为种种原因改回了 auto),然后再把 GO111MODULE 这个变量去掉,目前猜测会在 Go 2。太早去掉 GO111MODULE 的支持,会存在兼容性问题。
2). GOPROXY
此变量用于设置 Go 模块代理(Go module proxy),其作用是拉取源码时能够脱离传统的 VCS 方式,直接通过镜像站点来快速拉取。
镜像的好处多多,一个是防止某个版本的代码被有意或无意删除。第二是能将源码压为 zip 包,方便传输。最重要的 —— 可以做镜像加速站点,这在例如国内这种不稳定的网络环境下尤为重要。
GOPROXY 的默认值是:
https://proxy.golang.org,direct
然而 proxy.golang.org
在国内是无法访问的,所以我们使用 Go modules 时,需设置国内的 Go 模块代理:
$ go env -w GOPROXY=https://goproxy.cn,direct
信息: goproxy.cn 是一个由 CDN 提供商七牛云支持的非营利性项目。七牛云也是中国最早在生产环境中使用 Go 的公司之一,项目介绍请见:github.com/goproxy/goproxy.cn/blob… 。
GOPROXY 的值是一个以英文逗号 ,
分割的 Go 模块代理列表,可设置多个模块代理。将其设置为 off
,将会禁止 Go 在后续操作中使用任何 Go 模块代理。
direct 标志direct
标志意味着从源地址抓取(比如 GitHub 等)。
如我们设置 GOPROXY 的值为:
https://goproxy.cn,direct
则告诉 go get
在获取源码包时先尝试 [https://goproxy.cn](https://goproxy.cn)
,如果遇到 404 等错误时,再尝试从源地址抓取。
3). GOSUMDB
此值是 Go Checksum Database 的缩写,用于在拉取模块版本时(无论是从源站拉取还是通过 Go Module Proxy 拉取)保证拉取到的模块代码包未经过篡改,若发现不一致将会立即中止。
GOSUMDB 的默认值为:
sum.golang.org
在国内同样无法访问,所幸 GOSUMDB 可以被 Go Module Proxy 代理。我们所设置的模块代理 goproxy.cn
支持代理 sum.golang.org
。
另外,此变量还可设置为 off
,会禁止 Go 在后续操作中校验模块哈希。
4). GONOPROXY/GONOSUMDB/GOPRIVATE
这三个环境变量都是用在依赖了私有模块,这些模块 GOPROXY 和 GOSUMDB 都无法读取。
- GONOPROXY —— 设置不走 Go Proxy 的 URL 规则;
- GONOSUMDB —— 设置不检查哈希的 URL 规则;
- GOPRIVATE —— 设置私有模块的 URL 规则,会同时设置以上两个变量。
因为 GOPRIVATE 会同时设定以上两个,所以一般私有仓库使用 GOPRIVATE 即可。
以上三个值,都可使用逗号分隔来设置多个选项。例如:
$ go env -w GOPRIVATE="git.example.com,github.com/name/project"
设置后当 go get
时,前缀为 git.example.com
和 github.com/name/project
的模块都会被认为是私有模块。
我们也可以利用通配符,例如:
$ go env -w GOPRIVATE="*.example.com"
这样子设置的话,所有模块路径为 example.com 的子域名(例如:git.example.com)都将不经过 Go module proxy 和 Go checksum database,需要注意的是不包括 example.com 本身。