Tim Wang Tech Blog

go.mod 文件解析:直接与间接依赖

Direct vs Indirect Dependencies in go.mod file in Go 的中文翻译版本。

Module 是 Go的依赖工具。根据定义,Module是一组以 go.mod 为根目录的相关包的集合。 go.mod 文件定义了

  • Module 导入路径。
  • 用于成功构建项目的依赖项要求。它不仅定义了模块的依赖,同时也确定了依赖的版本。

Module中的依赖可以是两种类型:

  • Direct 在项目文件中被直接引用的直接依赖。
  • Indirect
    • 是module的直接依赖的二次依赖。
    • 在go.mod文件中被声明,但是没有被文件直接引用的依赖也被视为indirect依赖。

go.mod 文件理论上只记录了direct dependency。然而在下面的情况,它也会记录indirect dependency

  • 不在go.mod文件中出现的direct dependency,或者direct dependency项目中不包含go.mod文件。那么这个依赖将被添加到go.mod文件中,并且使用//indirect作为后缀
  • 没有被任何文件引用的依赖。

go.sum 将记录同时direct和indirect dependencies的校验和

接下来,我们来看一个direct dependency的例子。

git mod init learn

创建一个文件 learn.go

package main

import (
	"github.com/pborman/uuid"
)

func main() {
	_ = uuid.NewRandom()
}

请注意,我们在learn.go中用以下方式指定了依赖

"github.com/pborman/uuid"

所以 github.com/pborman/uuid 是一个我们的learn 项目的direct dependency,因为它是直接引用到learn.go中的。 现在让我们运行以下命令

go mod tidy

此命令将下载源文件中所需的所有依赖项。 运行此命令后,让我们再次检查 go.mod 文件的内容

# go.mod
module learn

go 1.14

require github.com/pborman/uuid v1.2.1

它列出了在 learn.go 文件中指定的direct dependency以及dependency的确切版本。 现在让我们检查一下 go.sum 文件.

# go.sum

github.com/google/uuid v1.0.0 h1:b4Gk+7WdP/d3HZH8EJsZpvV7EtDOgaZLtnaNGIu1adA=
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw=
github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=

go.sum 文件列出了模块所需的direct and indirect dependency的校验和。 github.com/google/uuidgithub.com/pborman/uuid 内部使用,因此它作为indirect dependency被记录在 go.sum 文件中。

以上我们通过在源文件中添加了一个依赖项,并使用 go mod tidy 命令下载该依赖项并将其添加到 go.mod 文件中。

让我们通过一个例子来理解它。 为此,让我们首先创建一个模块

git mod init learn

现在创建一个文件 learn.go

package main

import (
	"github.com/gocolly/colly"
)

func main() {
	_ = colly.NewCollector()

请注意,我们已将 learn.go 中的依赖项指定为

github.com/gocolly/colly

所以 github.com/gocolly/colly 是 learn 项目的direct dependency,因为它是直接导入到模块中的。让我们在 go.mod 文件中添加 colly v1.2.0 版本作为依赖

module learn

go 1.14

require	github.com/gocolly/colly v1.2.0

Now let’s run the below command

然后运行以下命令

go mod tidy

运行此命令后,让我们再次检查 go.mod 文件的内容。 由于 colly v1.2.0 版本没有 go.mod 文件,所以 colly 需要的所有依赖都将添加到 go.mod 文件中,并以 //indirect 作为后缀

# go.mod
module learn

go 1.14

require (
	github.com/PuerkitoBio/goquery v1.6.0 // indirect
	github.com/antchfx/htmlquery v1.2.3 // indirect
	github.com/antchfx/xmlquery v1.3.3 // indirect
	github.com/gobwas/glob v0.2.3 // indirect
	github.com/gocolly/colly v1.2.0
	github.com/kennygrant/sanitize v1.2.4 // indirect
	github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca // indirect
	github.com/temoto/robotstxt v1.1.1 // indirect
	golang.org/x/net v0.0.0-20201027133719-8eef5233e2a1 // indirect
	google.golang.org/appengine v1.6.7 // indirect
)

所有colly的其他依赖项都以 //indirect 为后缀。 所有direct 和 indirect dependencies的校验和也将记录在 go.sum 文件中。

我们还提到,任何未在任何源文件中导入的依赖项都将被标记为 //indirect。 为了验证这个说法,让我们删除上面创建的learn.go文件,同时清理 go.mod 文件以中相关行。 最后运行以下命令

go get github.com/pborman/uuid

现在检查 go.mod 文件的内容

module learn

go 1.14

require github.com/pborman/uuid v1.2.1 // indirect

请注意,github.com/pborman/uuid被记录为 //indirect,因为没有任何文件中直接引用它。