Go1.11 新特性 — 依赖管理工具:Go Modules 初步学习和使用笔记,内容包括:

  • 简单了解下 Go Module 以及一些新概念
  • 简单了解下 go mod 命令

1. Go Module

Go1.11 添加了对版本化模块的初步支持,版本化模块的提案在这里

Go 模块 是 Go 1.11 中选择加入的一个实验性功能,希望结合反馈并最终确定Go 1.12的功能。即使细节可能会发生变化,未来版本也会支持使用Go 1.11或vgo定义的模块。

  • 关于 Go 依赖管理的历程可以在这里了解(中文)

    通常我们会在一个 repo(仓库) 中创建一组 Go package,repo 的路径比如:github.com/myrepo/demo 会作为 go package 的导入路径(import path),Go 1.11给这样的一组在同一repo下面的packages赋予了一个新的抽象概念: module,并启用一个新的文件 go.mod 记录 module 的元信息。

接下来,我们了解几个新概念…

1.1. 新概念

这部分内容来自官网:Wiki Modules, 对部分内容做了简要翻译.

1.1.1. Modules

A module is a collection of related Go packages that are versioned together as a single unit. Most often, a single version-control repository corresponds exactly to a single module, but alternatively a single version-control repository can hold multiple modules.

一个模块就是把相关联的 Go 包作为单个单元一起版本化的集合。通常,单个版本控制仓库与单个模块是完全对应的,但是单个版本控制仓库也可以包含多个 modules

Modules must be semantically versioned(语义化版本) in the form v(major).(minor).(patch), such as v0.1.0, v1.2.3, or v3.0.1. The leading v is required. If using Git, tag released commits with their versions. (Optional privately hosted and public globally hosted “always on” immutable(不可变的) repositories such as Project Athens are in the works).

Note: 关于版本化

  • Modules 必须是语义化版本,格式:v<v.m.p>, 其中主版本号 v 必须存在
  • 在使用 Git 作为版本控制的项目中,项目发布记录的 tag 号也可以用作它们的版本
  • 一个 Repo 下可以拥有多个 modules

1.1.2. go.mod

A module is defined by a tree of Go source files with a go.mod file in the tree’s root directory. Module source code may be located outside of $GOPATH.

一个模块是由Go源文件树定义,且在源文件树的根目录下包含了一个 go.mod 文件。模块源代码可能位于 $GOPATH 之外。

Note:

  • go.mod 文件的作用:记录 module 的元信息,属于文本文件
  • 使用了 Go Module 后,源码不一定要在 GOPATH 中进行

All of the packages in a module share a common prefix – the module path. The go.mod file defines the module path via the module directive. For example, if you are defining a module for two packages example.com/my/thing/foo and example.com/my/thing/bar, the first line in your go.mod file typically would be module example.com/my/thing.

Module files may include comments and will look familiar to a Go programmer. Here is an example go.mod file:

1
2
3
4
5
6
7
module github.com/my/module/v3

require (
    github.com/some/dependency v1.2.3
    github.com/another/dependency v0.1.0
    github.com/additional/dependency/v4 v4.0.0
)

这里有四个指令可以使用:module、require、exclude、replace

  • require: 语句指定的依赖项模块
  • replace: 语句可以替换依赖项模块
  • exclude: 语句可以忽略依赖项模块

关于 exclude & replace 更详细的介绍请到原文查阅

1.1.3. Version Selection

If you add a new import to your source code that is not yet covered by a require in go.mod, any go command run (e.g., 'go build') will automatically look up the proper module and add the highest version of that new direct dependency to your module’s go.mod as a require directive. For example, if your new import corresponds to dependency M whose latest tagged release version is v1.2.3, your module’s go.mod will end up with require M v1.2.3, which indicates module M is a dependency with allowed version >= v1.2.3 (and < v2, given v2 is considered incompatible with v1).

这部分讲的是 go module 会自动更新 go.mod 文件,并将依赖关系写入其中…

1.1.4. Semantic Import Versioning

这部分内容主要是关于语义导入版本控制的,详细内容可在原文查阅

1.2. 特性开关 GO111MODULE

现在 modules 机制仍在早期阶段,所以golang提供了一个环境变量 GO111MODULE,默认值为auto,如果当前目录里有go.mod文件,就使用go modules,否则使用旧的GOPATH和vendor机制,因为在modules机制下go get只会下载go modules,这一行为会在以后版本中成为默认值,这里我们保持auto即可,如果你想直接使用modules而不需要从GOPATH过度,那么把 GO111MODULE 设置为on。

2. Go Module 命令:go mod

Go mod provides access to operations on modules.

Usage:

1
go mod <command> [<arguments>]

The commands are:

1
2
3
4
5
6
7
8
download    download modules to local cache             // 下载模块到本地缓存
edit        edit go.mod from tools or scripts           // 从工具或脚本来编辑 go.mod(记录module元信息的文件)
graph       print module requirement graph
init        initialize new module in current directory  // 在当前目录初始化新的 module,会生成 go.mod 文件
tidy        add missing and remove unused modules       // 添加丢失的或移除不再使用的 modules
vendor      make vendored copy of dependencies          // 将依赖包复制到项目下的 vendor 目录
verify      verify dependencies have expected content
why         explain why packages or modules are needed

Use “go help mod ” for more information about a command.

Others usefull:

1
2
go list -m all          显示依赖关系
go list -m -json all    显示详细的依赖关系

3. See Also

Thanks to the authors 🙂