学习GO:使用模块管理依赖关系

179 阅读4分钟

作为Go 1.11的一部分发布,现在在Go 1.16中默认启用,Go模块是管理依赖关系的推荐方式,在这篇文章中,我将介绍在日常工作中使用Go模块所需的步骤和命令。


什么是模块?

是存储在文件树中的Go软件包的集合,其根部是go.mod文件

这意味着根据定义,一个版本库不是一个包,而是根部有一个go.mod 的文件夹;所以换句话说,一个版本库在实践中可以有多个模块

go.mod 文件的内容定义如下。

  • 模块名称
  • Go版本
  • 必要的依赖(如果有的话)
  • 被替换的依赖关系(如果有的话)
  • 排除的依赖关系(如果有的话)

模块名称以及Go版本go.mod 中唯一需要的部分,因为在实践中你可以创建一个只使用标准库的模块。

例如,一个go.mod 可以是这样的。

module github.com/MarioCarrion/todo-api

go 1.16

require (
	github.com/confluentinc/confluent-kafka-go v1.7.0
	github.com/deepmap/oapi-codegen v1.5.1
	github.com/elastic/go-elasticsearch/v7 v7.12.0
	// ... more packages
)

创建一个模块

要创建一个模块,我们必须使用mod 工具,其形式为。

go mod init <module name>

在代表最终模块的根文件夹下,在上面的例子中,我用下面的方式来创建它。

go mod init github.com/MarioCarrion/todo-api

除了init之外,工具mod 还定义了其他有用的命令,如。

  • edit用来编辑go.mod 文件,旨在被CLI和脚本使用。
  • tidy用来添加缺失和删除未使用的模块。

还有一些,你可以使用go help mod ,以获得更多关于其他的细节。我认为在init之后使用最多的命令是tidy,因为在添加一个新模块作为依赖关系之后,你必须调用它来清理你的go.mod

使用模块工作

Go工具链中的其他工具都具有模块意识,因此,例如getbuildtest ,当检测到新的依赖关系时,它们会在幕后调用所需的mod工具来下载所需的包并更新go.mod

添加一个新的依赖,例如github.com/gorilla/mux ,可以用几种不同的方法来完成。

  1. 直接在新代码中添加导入,和
  2. 运行go mod downloadgo mod tidy

或者

  1. 运行go get github.com/gorilla/mux
  2. 将导入的内容添加到代码中,并
  3. 运行go mod downloadgo mod tidy

步骤的不同在于我们是否想明确地获得一个具体的版本,所以假设我们想获得版本v1.8.0 ,我们应该在第二个工作流程的第一步使用go get github.com/gorilla/mux@v1.8.0

这种版本管理机制带来了另一个需要了解的重要内容。Semantic Versioning(语义版本控制),我在谈到REST API的版本控制(Versioning REST APIs)时介绍了SemVer,其思想是完全一样的,模块作者在发布其模块时应遵循这些准则。

升级模块也遵循类似的工作流程,通过使用get ,例如,升级我们使用的模块。

go get -u github.com/gorilla/mux

这将会把模块更新到最新的版本,如果我们只是想看看是否有可用的更新,那么使用这样的方法就可以告诉我们。

$ go list -m -u github.com/elastic/go-elasticsearch/v7
github.com/elastic/go-elasticsearch/v7 v7.12.0 [v7.13.0]

上面的输出表明Elasticsearch包有一个新版本。

降级模块的步骤与我们指示版本时类似,但这次我们使用的是比我们目前拥有的版本更低的版本,例如。

go get github.com/gorilla/mux@v1.7.4

发布模块

就像我之前提到的,SemVer是Go中版本控制的一个基本部分,在创建Go模块时,理解并遵循这些准则是必须的;这些版本最终在版本控制系统中以标签形式表示。

例如要在一个刚好使用Git的模块中发布一个版本v1.2.3 ,我们应该用类似的方式创建一个标签。

git tag v1.2.3
git push origin --tags

在我们需要创建一个主要版本的情况下,例如从v1.x.x.v2.x.x ;有两种策略可以遵循。

  • 创建分支,或
  • 创建文件夹

当使用分支时,我们的想法是真的创建一个新的分支,例如在Git中。

git checkout -b v2

这种方法的一个真实例子是 github.com/olivere/elastic包,它是用于Elasticsearch的。

当使用文件夹时,我们的想法是用主要的版本名称创建一个文件夹,例如v2 ,这个文件夹将包括一个新的go.mod 。这方面的一个真实例子是 googleapis/gax-go/v2包。

对于这两种情况,我们必须修改go.mod 文件,在模块名称中注明v2 的版本,例如。

module github.com/MarioCarrion/todo-api/v2

go 1.16

// ... everything else