写在前面:
0x01 — 概念
Module 官方定义得很明确
A module is a collection of related Go packages that are versioned together as a single unit.
# 模块是相关Go包(Package)的集合,作为一个单一的单元一起进行版本管理.
Modules record precise dependency requirements and create reproducible builds.
# 模块记录了精确的依赖性要求并创建了可重复的构建。
Most often, a version control repository contains exactly one module defined in the repository root.
# 大多数情况下,一个版本控制库只包含一个在库根定义的模块。
(Multiple modules are supported in a single repository, but typically that would result in more work on an on-going basis than a single module per repository).
# 一个版本库支持多个模块,但通常这将导致在持续的基础上比每个存储库中的单个模块进行更多的工作
Summarizing the relationship between repositories, modules, and packages:
总结
A repository contains one or more Go modules.
# 一个资源库包含一个或多个Go模块
Each module contains one or more Go packages.
# 每个模块包含一个或多个Go包
Each package consists of one or more Go source files in a single directory.
# 每个包由单个目录中的一个或多个Go源文件组成
PS:版本库名称必须是三位标识,如v1.2.3、v2.1.3
0x02 — go.mod
Modules 由Go源代码目录树结构定义,结构的根目录也就是树顶有一个go.mod文件。定义的源代码位置可以是在GOPATH之外的目录。定义go.mod有四个指令: module、require、replace、exclude。
下面是一段示例:
module github.com/my/thing
require (
myPath/myPackage1 v0.0.0
myPath/myPackage2 v0.0.0
)
replace myPath/myPackage1 => ../myPath/myPackage1
replace myPath/myPackage2 => ../myPath/myPackage2
如上面module 名称为”github.com/my/thing“,module定义了两个包,分别为myPath/myPackage1和myPath/myPackage2,我们在引入myPath/MyPackage1下的函数或对象时需要首先全量引入myPath/myPackage1路径:
import "github.com/my/thing/myPath/myPackage1"
引入后则可可以通过myPackage1.XXX的形式来使用myPackage1下的方法或对象了。
上面可以知道module和require关键字的作用了,exclude和replace两个指令只对main模块也就是根模块进行操作,在构建项目时,通过这两个指令可以排除掉或替换掉指定名称的模块或包,可以不考虑依赖关系。以下通过两个示例表述下含义:
将依赖替换成指定版本:
replace example.com/some/dependency => example.com/some/dependency v1.2.3
将依赖替换成fork版本:
replace example.com/some/dependency => example.com/some/dependency-fork v1.2.3
将依赖替换成指定分支如master分支:
replace example.com/some/dependency => example.com/some/dependency-fork master
最重要的也是经常用的,如果你对本地的多个自定义的依赖库进行管理,可以用过replace方式在不改变源码存放位置的情况下进行指定位置:
replace myPackage => /home/myhome/package-v1
# replace myPackage => ../package-v2
注意: 上面的代码右侧引用的是本地系统路径,则引用目标路径下必须存在一个go.mod文件。如果该go.mod文件不存在,您可以使用 go mod init 生成。同时需要注意的是replace的对象必须要在require中定义才可以replace。
exclude 指令主要用于想要排除哪些包,比如我们有三个版本的myPackage,v1.0.0, v1.0.1, v1.0.2, 其中v1.0.1有重大问题,不能使用,但是在依赖中的依赖可能会存在依赖v1.0.1的情况,这样我们可以在go.mod中排除掉这个版本,其他引用这个版本依赖的位置也不会引用编译了,使用示例:
exclude github.com/google/gooo v1.0.1
为了有个清晰的轮廓,来个完整的go.mod示例:
module github.com/my/thing
// go.mod注释只能使用// 无法使用/**/
// require myPackage1 v1.2.3
// require myPackage2 v4.0.0
// require github.com/google/gooo v1.0.0
// 上面三行可以简化为下面形式,这是go里面常用的批量定义方式
require (
myPackage1 v1.2.3
myPackage2 v4.0.0
github.com/google/gooo v1.0.0
)
replace myPackage1 => ../package-v2
exclude github.com/google/gooo v1.0.1
在go.mod目录下同时会存在go.sum文件,是记录所依赖的项目的版本的锁定文件。
0x04 — module 命令
go mod可以通过命令进行创建整理,下载生成等操作:
Go mod provides access to operations on modules.
Note that support for modules is built into all the go commands,
not just 'go mod'. For example, day-to-day adding, removing, upgrading,
and downgrading of dependencies should be done using 'go get'.
See 'go help modules' for an overview of module functionality.
Usage:
go mod <command> [arguments]
The commands are:
download download modules to local cache (将模块下载到本地缓存)
edit edit go.mod from tools or scripts (从工具或脚本编辑go.mod)
graph print module requirement graph(打印模块需求图)
init initialize new module in current directory(在当前目录中初始化新模块,创建go.mod文件)
tidy add missing and remove unused modules (添加缺少的模块并删除未使用的模块,此方法为依赖模块刷新)
vendor make vendored copy of dependencies (制作依赖项的vendored副本,将依赖复制到vendor目录)
verify verify dependencies have expected content (验证依赖项具有预期的内容)
why explain why packages or modules are needed (解释为什么需要包或模块)
Use "go help mod <command>" for more information about a command.
- go mod download
将go.mod中描述的依赖转移至本地的vendor文件夹,如果不存在会创建,同时会生成一个modules.txt文件,用于描述整个工程所有模块。
- go mod init
此命令会在当前目录中初始化和创建一个新的 go.mod 文件,如果指定了参数,会
- go mod tidy
如果开发中存在很多已经不依赖的包, 可以使用 go mod tidy 命令来清除它 ,同时会下载需要依赖的包
- go mod verify
此命令会检查当前模块的依赖是否已经存储在本地缓存中,同时检查下载的包是否被修改。如果所有的模块都没有修改,那么会打印 all modules verified ,否则会打印变化的内容。
0x03 — 总结
熟悉了go mod后,可以不用关系GOPATH问题了,但是GOPATH是需要存在的,只是go mod帮我们托管了依赖的关系。go mod目前已经非常完善,推荐大家使用go mod来管理自己的依赖。