前文
- golang快速入门[1]-go语言导论
- golang快速入门[2.1]-go语言开发环境配置-windows
- golang快速入门[2.2]-go语言开发环境配置-macOS
- golang快速入门[2.3]-go语言开发环境配置-linux
- golang快速入门[3]-go语言helloworld
- golang快速入门[4]-go语言如何编译为机器码
- golang快速入门[5.1]-go语言是如何运行的-链接器
- golang快速入门[5.2]-go语言是如何运行的-内存概述
- golang快速入门[5.3]-go语言是如何运行的-内存分配
- golang快速入门[6.1]-集成开发环境-goland详解
- golang快速入门[6.2]-集成开发环境-emacs详解
- golang快速入门[7.1]-项目与依赖管理-gopath
题记
- 《庄子》‘逍遥游’有云:且夫水之积也不厚,则其负大舟也无力。覆杯水于坳堂之上,则芥为之舟;置杯焉则胶,水浅而舟大也。
- 我们今天要介绍的就是北冥神功—go module绝技,以吸收他人内力为己所用。而且别人的内力愈强 吸力愈大。极天下代码于一身,好不快活。
前言
- 在上文中,我们介绍了
gopath
的含义、功能、优劣、以及如何通过GOPATH来组织项目 - 在本文中,我们讲介绍
go module
的原理和用法以试图能够回答下面的几个问题- `go module`是什么?
- `go module`为什么需要?
- `go module`的基本使用方法是什么?
- `go module`如何管理版本与依赖?
- `go module`如何解决依赖的冲突问题?
- `go module` 环境变量的配置与使用方式?
- 如何搭建私有`module`镜像?
`go module`诞生的背景 & 为什么需要`go module`
在go module
之前,有一些问题长期困扰go语言的开发人员
- 能否将go工程代码脱离
gopath
之外 - 能否处理版本依赖问题并且自动选择最兼容的依赖版本
- 能否使用go工具本地管理依赖项,自定义依赖项
- go1.11开始支持,go1.13全面支持的
go modules
正是为了解决上面的问题诞生的,下面我们详细介绍go module
企图解决的问题
解决`import` 路径问题
- 在介绍
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 moudle 使用
Module缓存
为了加快构建程序的速度并快速切换、获取项目中依赖项的更新,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 2