大多数语言都有“依赖”、“包”等概念,Go语言的依赖处理经历了几回变革git
最先的时候,Go所依赖的全部的第三方库都放在GOPATH这个目录下面github
从v1.5开始开始引入vendor模式,若是项目目录下有vendor目录,那么go工具链会优先使用vendor内的包进行编译、测试等编程
从v1.11开始,引入了Go Module 做为依赖解决方案,到v1.14宣布Go Module已经能够用于生产环境,到v1.16版本开始Go Module默认开启json
GOPATH是什么,输入以下命令查看网络
# go env GOPATH GOPATH="/Users/ssgeek/go"
进入到该目录下,目录结构以下ide
# cd `go env GOPATH` # tree -L 2 . . ├── bin │ ├── dlv │ ├── go-outline │ ├── gomodifytags │ ├── gopkgs │ ├── goplay │ ├── gopls │ ├── gotests │ ├── impl │ └── staticcheck ├── pkg │ ├── mod │ └── sumdb └── src └── github.com ...
三个目录中存放的文件说明以下工具
bin //用来存放编译后的可执行文件 pkg //用于存放编译后生成的归档文件 src //用来存放go源码文件
在使用GOPATH的模式下,咱们须要将应用代码存放在固定的$GOPATH/src目录下,而且若是执行go get来拉取外部依赖会自动下载并安装到$GOPATH目录下测试
第三方套件只要不是官方库,都须要放置在GOPATH/src的路径下才可使用ui
go get最经常使用在当咱们想用别人公开在GitHub上的套件,能够帮咱们从网络clone到GOPATH/src里面。虽然这样很方便,可是会发现GOPATH/src下会很复杂,除了有你本身开发的代码目录,同时也包含其余第三方库的专属目录加密
咱们给不一样的项目设置不一样的GoPath,优势很是明显:
便于管理项目,每一个项目都是不一样的GoPath,这对于咱们管理多个Golang项目而言,可以很是清晰的处理项目结构。若是咱们把全部项目都放在同一个GoPath的src包下,那么项目的结构就会变得很是混乱,难以管理
可是当咱们须要依赖第三方的包的时候,不一样的项目设置不一样的GoPath的缺点也很是明显:
为了解决GOPATH的问题,所以官方在1.11开始推出了Go Modules的功能。Go Modules解决方式很像是Java看到Maven的作法,将第三方库储存在本地的空间,而且给项目代码去引用
总共能够设置三种不一样的值
默认值,go命令会根据当前目录来决定是否启用modules功能。须要知足两种情形:
该目录不在GOPATH/src/下
当前或上一层目录存在go.mod文件
go命令会使用modules,而不会去GOPATH目录下查找。
go命令将不会支持module功能,寻找依赖按照之前GOPATH的作法去寻找
目前1.16版本默认将这个参数设置成on,并且可能以后的版本会弃用掉GO111MODULE,所以建议要开发Go项目时就再也不使用GOPATH了,而是采用Go Modules的作法,所以建议都设定为on
采用Go Modules,下载下来的第三方依赖就位于GOPATH/pkg/mod目录下
go mod init <module name>
<module name>可填可不填,不填的话预设就是默认的文件名称go.mod
在此文件中能够写如下几个关键字:
定义模组路径
定义go语言version
指定依赖,预设是最新版,能够指定版本号
排除该依赖和其版本
使用不一样的依赖版本并替换原有的依赖版本注解
indirect表明被间接导入的依赖包
假设如今我要引入GitHub上的gin-gonic/gin的依赖,以下定义:
module myProject go 1.16 require github.com/gin-gonic/gin v1.6.3
再执行如下指令:
go mod xxx
会将须要的依赖安装在GOPATH/pkg/mod目录里面
gin@v1.4.0 gin@v1.6.3 gin@v1.7.1
除了go.mod以外,go命令还维护一个名为go.sum的文件,其中包含特定模块版本内容的预期加密哈希
go命令使用go.sum文件确保这些模块的将来下载检索与第一次下载相同,以确保项目所依赖的模块不会出现意外更改,不管是出于恶意、意外仍是其余缘由。 go.mod和go.sum都应检入版本控制。
go.sum不须要手工维护,因此能够不用太关注
只要有开启go modules功能,go get 就不会像之前同样在GOPATH/src下放置依赖,而是会放在GOPATH/pkg/mod里面,而且go.mod会写好引入
经常使用
go mod init:初始化go mod, 生成go.mod文件,后可接参数指定 module 名,上面已经演示过。 go mod download:手动触发下载依赖包到本地cache(默认为$GOPATH/pkg/mod目录) go list -m -json all:以 json 的方式打印依赖详情
其余
go mod graph: 打印项目的模块依赖结构 go mod tidy :添加缺乏的包,且删除无用的包 go mod verify :校验模块是否被篡改过 go mod why: 查看为何须要依赖 go mod vendor :导出项目全部依赖到vendor下 go mod edit :编辑go.mod文件
GoPath所引出的问题,就是由于第三方类库的包所致使的,因此在有了GoModule以后,GoPath和GoModule就分别负责不一样的职责,共同为Golang项目服务
GoPath用来存放咱们从网上拉取的第三方依赖包
GoModule用来存放咱们本身的Golang项目文件,当本身的项目须要依赖第三方的包的时候,咱们经过GoModule目录下的一个go.mod文件来引用GoPath目录pkg包下的mod文件夹下的第三方依赖便可
这样以来,既解决了原来只能局限在GoPath目录src包下进行编程的问题,也解决了第三方依赖包难以管理和重复依赖占用磁盘空间的问题