1. 简介
GOPATH
模式下,依赖包存储在$GOPATH/src
,该目录下只保存特定依赖包的一个版本,而在GOMODULE
模式下,依赖包存储在$GOPATH/pkg/mod
,该目录中可以存储特定依赖包的多个版本。
需要注意的是$GOPATH/pkg/mod
目录下有个cache
目录,它用来存储依赖包的缓存,简单说,go命令每次下载新的依赖包都会在该cache
目录中保存一份。关于该目录的工作机制我们留到GOPROXY
章节时再详细介绍。
接下来,我们使用开源项目github.com/google/uuid
为例分别说明GOPATH模式和GOMODULE模式下特定依赖包存储机制。在下面的操作中,我们会使用GO111MODULE
环境变量控制具体的模式:
- export GO111MODULE=off切换到GOPATH模式
- export GO111MODULE=on切换到GOMODULE模式
2. GOPATH 依赖包存储
为了实验GOPATH模式下依赖包的存储方式,我们可以使用以下命令来获取github.com/google/uuid
:
# export GO111MODULE=off
# go get -v github.com/google/uuid
在GOPATH模式下,go get
命令会将依赖包下载到$GOPATH/src/google
目录中。
该命令等同于在$GOPATH/src/google
目录下执行git clone https://github.com/google/uuid.git
,也就是$GOPATH/src/google.com/google/uuid
目录中存储的是完整的仓库。
3.GOMODULE 依赖包存储
为了实验GOMODULE
模式下依赖的存储方式,我们使用以下命令来获取github.com/google/uuid
:
# export GO111MODULE=on
# go get -v github.com/google/uuid
# go get -v github.com/google/uuid@v1.0.0
# go get -v github.com/google/uuid@v1.1.0
# go get -v github.com/google/uuid@v1.1.1
在GOMODULE模式下,go get命令会将依赖包下载到$GOPATH/pkg/mod目录下,并且按照依赖包的版本分别存放。(注:go get命令不指定特定版本时,默认会下载最新版本,即v1.1.1,如软件包有新版本发布,实验结果将有所不同。)
此时$GOPATH/pkg/mod
目录结构如下:
${GOPATH}/pkg/mod/github.com/google
├── uuid@v1.0.0
├── uuid@v1.1.0
├── uuid@v1.1.1
相较于GOPATH模式,GOMODULE有两处不同点:
- 一是依赖包的目录中包含了版本号,每个版本占用一个目录;
- 二是依赖包的特定版本目录中只包含依赖包文件,不包含.git目录;
由于依赖包的每个版本都有一个唯一的目录,所以在多项目场景中需要使用同一个依赖包的多版本时才不会产生冲突。另外,由于依赖包的每个版本都有唯一的目录,也表示该目录内容不会发生改变,也就不必再存储其位于版本管理系统(如git)中的信息。
4.包名大小写敏感问题
有时我们使用的包名中会包含大写字母,比如github.com/Azure/azure-sdk-for-go
,GOMODULE
模式下,在存储时会将包名做大小写编码处理,即每个大写字母将变与!+相应的小写字母
,比如github.com/Azure
包在存储时将会被放置在$GOPATH/pkg/mod/github.com/!azure
目录中。
需要注意的是,GOMODULE
模式下,使用go get命令时,如果不小心将某个包名大小写搞错,比如github.com/google/uuid
写成github.com/google/UUID
时,在存储依赖包时会严格按照go get命令指示的包名进行存储。
如下所示,使用大写的UUID:
[root@wsl-maoyifei]# go get -v github.com/google/UUID@v1.0.0
go: finding github.com v1.0.0
go: finding github.com/google v1.0.0
go: finding github.com/google/UUID v1.0.0
go: downloading github.com/google/UUID v1.0.0
go: extracting github.com/google/UUID v1.0.0
github.com/google/UUID
由于github.com/google/uuid
域名不区分大小写,所以使用github.com/google/UUID
下载包时仍然可以下载,但在存储时将会严格区分大小写,此时$GOPATH/pkg/mod/google/
目录下将会多出一个d@v1.0.0"">
!u!u!i!d@v1.0.0`目录:
${GOPATH}/pkg/mod/github.com/google
├── uuid@v1.0.0
├── uuid@v1.1.0
├── uuid@v1.1.1
├── !u!u!i!d@v1.0.0
在go get
中使用错误的包名,除了会增加额外的不必要存储外,还可能会影响go命令解析依赖,还可能将错误的包名使用到import指令中,所以在实际使用时应该尽量避免。