前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go Modules 详解

Go Modules 详解

作者头像
全栈程序员站长
发布2022-07-19 10:47:45
8290
发布2022-07-19 10:47:45
举报

大家好,又见面了,我是全栈君。

Go 1.11 和 Go 1.12 包含了初步的 Go Modules 支持,且计划在 2019 年 8 月发布的 Go 1.13 会在所有开发过程中默认使用 Go Modules。

Go Modules 是为了提升使用其他开发者代码,即添加 依赖项(模块、包) 时的体验,也是为了让代码的正确性、安全性得到保障。并且 Go Modules 可以使用 GOPROXY 环境变量来解决中国大陆无法使用 go get 的问题。

所以学习跟 Go Modules 有关的知识是很有必要的。

Go Modules 详解
Go Modules 详解

模式

Go Modules 在 Go 1.11 及 Go 1.12 中有三个模式,根据环境变量 GO111MODULE 定义:

  • 默认模式(未设置该环境变量或 GO111MODULE=auto):Go 命令行工具在同时满足以下两个条件时使用 Go Modules:
    • 当前目录不在 GOPATH/src/ 下;
    • 在当前目录或上层目录中存在 go.mod 文件。
  • GOPATH 模式(GO111MODULE=off):Go 命令行工具从不使用 Go Modules。相反,它查找 vendor 目录和 GOPATH 以查找依赖项。
  • Go Modules 模式(GO111MODULE=on):Go 命令行工具只使用 Go Modules,从不咨询 GOPATH。GOPATH 不再作为导入目录,但它仍然存储下载的依赖项(GOPATH/pkg/mod/)和已安装的命令(GOPATH/bin/),只移除了 GOPATH/src/。

Go 1.13 默认使用 Go Modules 模式,所以以上内容在 Go 1.13 发布并在生产环境中使用后都可以忽略。

核心文件:go.mod

以下就是 go.mod 文件的一个最全面的示例:

1 2 3 4 5 6 7 8 9 10

module my/thing go 1.12 require other/thing v1.0.2 // 这是注释 require new/thing/v2 v2.3.4 // indirect require( new/thing v2.3.4 old/thing v0.0.0-20190603091049-60506f45cf65 ) exclude old/thing v1.2.3 replace bad/thing v1.4.5 => good/thing v1.4.5

很全面,也很复杂。但其实 go.mod 文件在实际项目没有这么复杂,而且一旦该文件存在,就不需要额外的步骤:像 go build、go test,甚至 go list 这样的命令都会根据需要自动添加新的依赖项以满足导入。

但现在我们还是来详细了解 go.mod 文件的组成:

go.mod 文件是面向行的, 当前模块(主模块)通常位于第一行,接下来是根据路径排序的依赖项。

每行包含一个指令,由一个前导动词后跟参数组成。

所有前导动词的作用如下:

  • module:定义模块路径。
  • go:设置预期的语言版本。
  • require:要求给定版本或更高版本的特定模块。
  • exclude:排除特定版本模块的使用,不允许的模块版本被视为不可用,并且查询无法返回。
  • replace:使用不同的模块版本替换原有模块版本。

前导动词还可以按块的方式使用,用括号创建一个块(第 5-8 行),就像在 Go 语言中的导入一样:

1 2 3 4 5

import ( "errors" "fmt" "log" )

注释(第 3-4 行)可以使用单行 // 这是注释 注释,但不能使用多行 /* 这是注释 */ 注释。而 indirect 注释(第 4 行)标记了该模块不是被当前模块直接导入的,只是被间接导入。

go.mod 文件只存在于在模块的根目录下,子目录中的导入路径会使用模块的导入路径 + 子目录路径的形式。例如:如果创建了一个名叫 world 的子目录,并不需要在子目录中使用 go mod init 命令,Go 命令行工具会自动识别它作为 hello 模块的一部分,所以它的导入路径为 hello/world。

Go 命令行工具会自动处理 go.mod 中指定的模块版本。当源代码中 import 指向的模块不存在于 go.mod 文件中时,Go 命令行工具会自动搜索这个模块,并将最新版本(最后一个 tag 且非预发布的稳定版本)添加到 go.mod 文件中。

如果没有 tag,则使用伪版本(第 7 行),这是一种版本语法,专门用于标记没有 tag 的提交(一些 golang.org/x/ 下的包就是没有 tag 的)。如:v0.0.0-20190603091049-60506f45cf65

前面部分为语义化版本号,用于标记版本;中间部分为 UTC 的提交时间,用于比较两个伪版本以其确定先后顺序;后面部分是 commit 哈希的前缀,用于标记该版本位于哪个 commit。

版本管理文件:go.sum

示例如下:

1 2 3 4 5 6

github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/gin-gonic/gin v1.4.0 h1:3tMoCCfM7ppqsR0ptz/wi1impNpT7/9wQtMZ8lr1mCQ= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= github.com/golang/protobuf v1.3.1 h1:YF8+flBXS5eO826T4nzqPrxfhQThhXl0YzfuUPu4SBg= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=

每行由模块导入路径、模块的特定版本和预期哈希组成。

在每次缺少模块时,如果缓存中不存在,则需要下载并计算其哈希添加到 go.sum 中;如果缓存中存在,则需要匹配 go.sum 中的已有条目。

这样,构建软件的用户就可以使用哈希验证其构建是否跟你的构建相同(go mod verify),而无论他们怎样获取依赖项,都可以得到相同的版本。同时也保证了项目依赖不会发生预料之外的恶意修改和其他问题。这也是为什么要将 go.sum 文件加入版本管理(Git)的原因。

再加上 Go Modules 选择的是最小版本选择策略(默认使用构建中涉及的每个模块的最旧允许版本,使得新版本的发布对构建没有影响)就可以实现可重现的构建(在重复构建时产生相同的结果)。

语义化版本

什么是语义化版本?语义化版本是一套由 Gravatars 创办者兼 GitHub 共同创办者 Tom Preston-Werner 所建立的约定。在这套约定下,语义化版本号及其更新方式包含了很多有用的信息。

语义化版本号格式为:X.Y.Z(主版本号.次版本号.修订号),使用方法如下:

  • 进行不向下兼容的修改时,递增主版本号。
  • API 保持向下兼容的新增及修改时,递增次版本号。
  • 修复问题但不影响 API 时,递增修订号。

举个例子,有一个语义化版本号为:v0.1.2,则其主版本号为 0,次版本为 1,修订号为 2。而前面的 v 是 version(版本)的首字母,是 Go 语言惯例使用的,标准的语义化版本没有这个约定。

所以在使用 Go 命令行工具或 go.mod 文件时,就可以使用语义化版本号来进行模块查询,具体规则如下:

  • 默认值(@latest):将匹配最新的可用标签版本或源码库的最新未标签版本。
  • 完全指定版本(@v1.2.3):将匹配该指定版本。
  • 版本前缀(@v1@v1.2):将匹配具有该前缀的最新可用标签版本。
  • 版本比较(@<v1.2.3@>=v1.5.6):将匹配最接近比较目标的可用标签版本。< 则为小于该版本的最新版本,> 则为大于该版本的最旧版本。当使用类 Unix 系统时,需用引号将字符串包裹起来以防止大于小于号被解释为重定向。如:go get 'github.com/gin-gonic/gin@<v1.2.3'
  • 指定某个 commit(@c856192):将匹配该 commit 时的版本。
  • 指定某个分支(@master):将匹配该分支版本。
Go Modules 详解
Go Modules 详解

如上图所示,为了能让 Go Modules 的使用者能够从旧版本更方便地升级至新版本,Go 语言官方提出了两个重要的规则:

  • 导入兼容性规则(import compatibility rule):如果旧包和新包具有相同的导入路径,则新包必须向后兼容旧包。
  • 语义化导入版本规则(semantic import versioning rule):每个不同主版本(即不兼容的包 v1v2)使用不同的导入路径,以主版本结尾,且每个主版本中最多一个。如:一个 rsc.io/quote、一个 rsc.io/quote/v2、一个 rsc.io/quote/v3

而与 Git 分支的集成如下:

Go Modules 详解
Go Modules 详解

vendor 目录

以前使用 vendor 目录有两个目的:

  • 可以使用依赖项的确切版本用来构建。
  • 即使原始副本消失,也能保证这些依赖项是可用的。

而模块现在有了更好的机制来实现这两个目的:

  • 通过在 go.mod 文件中指定依赖项的确切版本。
  • 可用性则由缓存代理($GOPROXY)实现。

而且 vendor 目录也很难管理这些依赖项,久而久之就会陷入与 node_modules 黑洞一样的窘境。

Go Modules 详解
Go Modules 详解

所以,默认情况下使用 Go Modules 将完全忽略 vendor 的依赖项,但是为了平稳过度,可以使用 go mod vendor 命令可以创建 vendor 目录。

并在 Go 命令行工具使用 -mod=vendor 参数,如:go test -mod=vendor ./...;或设置环境变量 GOFLAGS 为 -mod=vendor,这样会假定 vendor 目录包含正确的依赖项副本,并忽略 go.mod 文件中的依赖项描述来构建。

环境变量 GOPROXY

设置环境变量 GOPROXY 可以解决中国大陆无法使用 go get 的问题:

export GOPROXY=https://goproxy.io 写入 Shell 的配置文件即可。

常用命令

  • go mod init:创建一个新模块,初始化 go.mod 文件,参数为该模块的导入路径,推荐使用这种形式。如:go mod init github.com/linehk/example
  • go get:更改依赖项版本(或添加新的依赖项)。
  • go buildgo test 等命令:Go 命令行工具会根据需要添加新的依赖项。如:go test ./...,测试当前模块。
  • go list -m all:打印当前模块依赖。
  • go mod tidy:移除无用依赖。
  • go list -m -versions github.com/gin-gonic/gin:列出该模块的所有版本。
  • go mod verify:验证哈希。

与 GoLand 集成

在 GoLand 2019.1.3 中使用 Go Modules 需要进行两个设置:

  • Preferences -> Go -> Go Modules (vgo),勾选 Enable Go Modules (vgo) integration 以启用 Go Modules,并在 Proxy 输入框中输入 https://goproxy.io。如图所示:
Go Modules 详解
Go Modules 详解
  • Preferences -> Go -> GOPATH,勾选上 Index entire GOPATH 以索引整个 GOPATH,不然无法导入包。如图所示:
Go Modules 详解
Go Modules 详解

进行如上设置后,就可以在导入不在缓存中的包时,点击 Sync packages of… 下载该包了:

Go Modules 详解
Go Modules 详解

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/111521.html原文链接:https://javaforall.cn

本文参与?腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022年2月1,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体同步曝光计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 模式
  • 核心文件:go.mod
  • 版本管理文件:go.sum
  • 语义化版本
  • vendor 目录
  • 环境变量 GOPROXY
  • 常用命令
  • 与 GoLand 集成
相关产品与服务
命令行工具
腾讯云命令行工具 TCCLI 是管理腾讯云资源的统一工具。使用腾讯云命令行工具,您可以快速调用腾讯云 API 来管理您的腾讯云资源。此外,您还可以基于腾讯云的命令行工具来做自动化和脚本处理,以更多样的方式进行组合和重用。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
http://www.vxiaotou.com