关于Go Modules (1)


人工翻译 参考 https://go.dev/ref/mod#introduction


Go Modules

Go使用modules进行依赖管理。


模块、包、版本

modules是相关Go包的集合,是源代码交换和版本控制单元。
(module下文称之为 模块)

模块可以从版本控制存储库或模块代理服务器下载。

模块由在go.mod文件中声明的模块路径以及有关依赖项信息标识。
模块根目录是包含go.mod文件的目录。
主模块是包含go command路径的模块。

模块中的每个包都是同一目录一起编译的源文件的集合。
包路径是与包含包子目录连接的模块路径(相对于模块根目录)。
例如,模块golang.org/x/net在目录中包含一个包html,该包的路径是golang.org/x/net/html。

模块路径

一个module指令决定主模块的路径。
一个go.mod文件至少要包括一个module指令。

一般来说,在我们的go.mod文件中,第一行就是:
module xxx.xxx.xxx/myproject/client_service 类似的

ModuleDirective = “module” (ModulePath | “(” newline ModulePath newline “)” newline

一个module path 应该描述这个模块的作用和怎样找到它。
通常module由存储库根路径、存储库中的目录和主要版本后缀组成

  • 大多数模块都定义在根目录
  • 如果没有定义在根目录,模块子目录是模块路径中命名目录的部分
  • 如果模块以主要版本2或者更高版本发布,模块路径必须以主要版本后缀结尾(这个后缀可能并不是目录名称的一部分)

版本

一个版本定义一个模块的不可变快照,每个版本都以 v 开头,跟着语义版本。
一个 semantic version (语义版本) 包括三个由点分割的非负整数。

主要.次要.补丁版本

补丁版本可以跟一个连字符开头的可预选发布字符串。

比如v1.0.1-pre

  • 在对模块的公共接口或记录的功能进行向后不兼容的更改,必须增加主要版本,并且必须将次要和补丁置为0
  • 向后兼容的更改,要增加次要版本,将补丁置0
  • 补丁版本必须不影响模块公共接口,一般作为错误修复和优化

在主模块中,go command命令会自动转变不符合约定的版本名称。

伪版本是一种特殊格式的预发布版本,对版本控制存储库中特定修订的信息进行编码。

比如 v.0.0.0-202202020202-dddad

将包解析为模块

当 go command 使用包路径加载包时,需要决定哪个模块提供了这个包。

比如说import了 example.com/a/b,那么example.com/a就是在构建目录里。然后go command就会去查找,是否example.com/a里有b这个目录,并且该目录里面有go文件。

对于每个在GOPROXY中的入口,go command 请求每个模块最新版本的路径(可能提供这个包的)。对于每个成功请求到的模块路径,go command 会下载模块。如果有多个模块都包含请求的包,那么有最长路径的模块将被使用。


go.mod 文件

一个模块是使用UTF-8编码定义在go.mod文件里,在它的根目录。
go.mod文件一行有一个单独的指令。

go.mod文件被设计为认练可读并且机器可写。go command 也提供了很多子命令用来修改go.mod。

词汇元素

当go.mod文件被解析时,它的内容被切分成一系列标记。

标记的种类有 :
空白,注释,标点,关键字,标识符,字符串

注释允许// 不允许/**/
标点符号是( ) =>
关键字区分go.mod文件中不同的指令。允许的关键字是:module、go、require、replace、exclude、retract。

语法

go.mod使用的是扩展巴科斯EBNF范式 (PS:EBNF可以理解为一种常见的约定,比如{}的优先级高于[],这个范式就是用来做这种符号的意义和优先级约定的)

GoMod = {Directive}.
Directive = ModuleDirective |
GoDirective|
RequireDirective|
ExcludeDirective|
ReplaceDirective|
RetraceDirective.

module指令

module hhhh.com/rpc/service

module指令定义主模块的路径。
一个go.mod文件必须只包含一个module指令。

go指令

go 1.17

go指令用于表明一个模块是在假设给定版本的go的语义下编写的。
go指令最初是想支持go语言的向后不兼容的更改。
但是引入模块后,就算没有不兼容的更改,go指令仍然影响使用新语言的特性,
此外,go命令还会根据指定版本去更改其行为。

require指令

用来声明给定模块依赖的最低版本要求。
对于需要的每个模块版本,会加载符合的版本和包含的依赖。
当所有依赖的都被加载,会使用minimal version selection MVS 来处理去产生 构建列表

(PS:MVS这种算法在模块的有向图上运行–由go.mod指定,图中的每个顶点代表一个模块版本,每条边代表一个依赖项的最低版本要求–由require指定,该图也可以由主模块的exclude和replace去进行更改。MVS从主模块开始遍历图,跟踪每个模块需要的最高版本。在遍历结束是时,最高要求的版本构成构建列表:是满足所有要求的最低版本,,,这个后面单出一篇博客)
https://go.dev/ref/mod#minimal-version-selection

go 命令会自动加上// indirect 注释在某些依赖上,这表明这是间接的依赖。
间接依赖一般有这些场景:直接依赖没有启用go module; 直接依赖的go.mod缺失部分依赖。

exclude指令

该指令阻止go命令加载模块版本,且仅适用于主模块的go.mod文件,就是说如果其他项目引用了该项目是会被忽略的。

一般开发时很少使用。

replace指令

该指令将模块的特定版本或者所有版本内容替换为其他地方的内容。
可以使用另一个模块路径和版本或特定于平台的文件路径来指定替换。
如果=>的左侧标明了版本,那么仅仅替换指定版本,其他版本正常访问。否则就会替换所有版本。
如果右侧的版本不是本地路径,那必须是个有效路径。这种情况下,相同的模块版本不得同时出现在构建列表中。

注意!!!,replace单独的指令是不会将模块加载到模块图(上面MVS中提到的)中的。必须要在主模块或者依赖项文件中引用被替换的模块版本的require指令。就是说如果没有require=>的左侧,右侧就会无效。

replace的使用场景

retract指令

该指令指示不应该依赖于定义的模块的retract版本或版本范围。
当版本过早发布或者发布后有严重问题时,这个指令很有用,就是用来撤回版本。

具体来说就是,如果我发现我的某版本代码有问题,但是很不幸被其他人已经依赖了。我可以发布一个新版本,然后在go.mod里写上 retract v.0.1.1 。
发布之后,所有引用该库的人执行go list就会看到提醒,这个版本被撤回了。

(PS:这个是1.16的新特性~)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值