详解 Go (Golang) 中的 go.sum 和 go.mod 文件

447 阅读4分钟

概述

模块是对依赖管理的支持。根据定义,模块是相关包的集合,其根为go.mod。 go.mod文件定义了

  • 模块导入路径。

  • 创建模块所用的 go 版本

  • 成功构建的模块的依赖关系要求。它定义了两个项目的依赖项要求,并将它们锁定到正确的版本。

go.sum

该文件列出了版本所需的直接和间接依赖项的校验和。值得一提的是,有了go.mod文件就可以成功构建go 程序。他们为什么需要go.sum文件?go.sum文件中的校验和用于验证每个直接和间接依赖项的校验和,以确认它们都没有被修改。

我们上面提到 go.mod 文件列出了模块的依赖关系要求。现在模块的依赖可以有两种

  • 直接- 直接依赖是模块直接导入的依赖。

  • 间接- 这是由模块的直接依赖项导入的依赖项。此外, go.mod文件中提到但未在模块的任何源文件中导入的任何依赖项也被视为间接依赖项。

go.mod文件仅记录直接依赖关系。但是,在以下情况下它可能会记录间接依赖关系

  • 直接依赖项的go.mod文件中未列出的任何间接依赖项,或者如果直接依赖项没有 go.mod 文件,则该依赖项将添加到 go.mod 文件中,并// indirect作为后缀。我们将在本文后面看到一个例子,以便更好地了解这一点。

另请注意,go.mod和go.sum文件都应签入版本控制系统 (VCS),例如 git

例子

让我们看一个示例来了解我们上面讨论的有关go.modgo.sum文件的内容。为此,我们首先创建一个模块

go mod init learn

此命令将在同一目录中创建一个**go.mod文件。**让我们检查一下该文件的内容。cat go.mod

module learn

go 1.14

当第一次使用 init 命令创建模块时,go.mod文件只有两件事

  • 顶部模块的导入路径
module learn
  • 创建模块所用的 go 版本
go 1.14

由于它是一个空模块,因此尚未指定任何直接依赖项。让我们在同一目录中创建一个名为uuid.go的文件,其中包含以下内容

uuid.go

package main

import (
	"fmt"
	"strings"

	"github.com/pborman/uuid"
)

func main() {
	uuidWithHyphen := uuid.NewRandom()
	uuid := strings.Replace(uuidWithHyphen.String(), "-", "", -1)
	fmt.Println(uuid)
}

请注意,我们也在 uuid.go 中导入了依赖项

"github.com/pborman/uuid"

让我们运行以下命令

go mod tidy

此命令将下载源文件中所需的所有依赖项,并使用该依赖项更新go.mod文件。运行此命令后,我们现在再次检查go.mod文件的内容。cat go.mod

module learn

go 1.14

require github.com/pborman/uuid v1.2.1

它列出了 uuid 文件中指定的直接依赖项以及依赖项的确切版本。现在我们也检查一下go.sum文件

cat go.mod

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文件列出了模块所需的直接和间接依赖的校验和。 github.com /google/uuid由github.com /pborman/uuid内部使用。它是模块的间接依赖项,因此记录在go.sum文件中。

我们现在也可以运行这个文件,它将给出正确的输出

go run uuid.go

输出

e594dc4d9a754bcb83b56e89b18b4b46

我们上面提到,在下面的情况下,go.mod文件可能包含间接依赖项。

  • 直接依赖项的go.mod文件中未列出的任何间接依赖项,或者如果直接依赖项没有 go.mod 文件,则该依赖项将添加到 go.mod 文件中,并// indirect作为后缀。我们将在本文后面看到一个例子,以便更好地了解这一点。

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

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是学习模块的直接依赖项,因为它是直接导入到模块中的。现在让我们运行以下命令

go mod tidy

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

cat 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
)

所有其他依赖项均以**//indirect**为后缀。所有直接和间接依赖项的校验和也将记录在 go.sum 文件中。