Go 1.18 新特性:多模块工作区模式
本文分享自华为云社区《一起看看 Go 1.18 新特性之多模块工作区模式》,作者:宇宙之一粟 。
引言
2022 年,Go 团队发布 Go 1.18 ,作为一个大的版本变动,Go 1.18 理所当然涵盖了许多的新功能、Go 团队也提到是 Go 语言发布以来做的最大的一次变动,并且性能改进很大。
其中一个功能,就是提供了一个多模块工作区的模式。官方博客说明如下:
该段文字的翻译:Go 模块几乎已被普遍采用,Go 用户在我们的年度调查报告中对 Go 模块给予非常高的满意度得分。在我们的 2021 年用户调查中,用户跨多个模块工作识别出不同的模块最常见的挑战。在 Go 1.18 中,我们使用新的 Go 工作区模式解决了这个问题,这使得使用多个模块变得简单。
Go 的依赖管理,或 Go Module,已经存在了好几年,但一直受到很多批评和改进。在 Go 1.18 推出多模块工作区模式——Multi-Module Workspaces,用以支持模块的多个工作空间,我们来看看到底有什么特别。
先决条件
安装 Go 1.18 或更高版本。
用于编辑代码的工具。您拥有的任何文本编辑器都可以正常工作。本文使用 VSCode。
一个命令终端。 Go 在 Linux 和 Mac 上的任何终端以及 Windows 中的 PowerShell 或 cmd 上都能很好地工作。本文使用 Ubuntu 。
工作区模式
每天处理 Go 项目时,有两个经典问题特别无趣:
依赖于本地 replace 模块
依赖于本地未发布的模块。
replace module
第一种场景: 例如,在一个 Go 项目中,我们会使用 replace 来解决一些本地依赖或自定义代码。我们将在 go.mod 文件中使用 replace 来执行此操作。
如下的代码:
这在链接本地开发时允许准确性。但是同时又会有问题:
本地路径:替换设置本质上转换为本地路径,这意味着每个人都是不同的。
远程依赖:文件更改会上传到 Git 仓库,所以如果你不小心上传了一个文件,会影响到其他开发者,或者每次上传都得改回来。
Unpublished modules
第二种场景: 当你在做一个本地的 Go 项目时,你可能同时在做多个库(项目库、工具库、第三方库)。
看如下的代码:
如果此时运行 go run 或 go mod tidy,它将不起作用并且会失败。
将抛出如下错误。
此异常是因为库 http://github.com/eddycjy/pkgutil 在 GitHub 上不可用,因此无法拉取。
解决方案: 在 Go 1.18 之前,我们要么替换,要么直接上传到 Github,依赖将由 Go 工具链拉取。
很多用户对此提出质疑:Go 的所有依赖项都必须上传到 GitHub,并具有强绑定吗?
这对新人非常不友好。
Workspace model
经过社区多轮反馈,Michael Matloob 提出提案:Proposal: Multi-Module Workspaces in cmd/go,经过广泛讨论和实施,Go 1.18 正式实施。
新提案的核心概念之一是添加了 go work 工作空间概念,该概念针对 Go Module 依赖管理模型。
可以在本地项目的 go.work 文件中设置一系列依赖的模块本地路径,然后将路径下的模块组合成当前 Go 项目的工作空间,即 N 个 Go Modules into 1 Go Work,用工作空间具有最高的读取优先级。
我们可以通过 go help 看到这一点,如下所示。
只需执行 go work init 来初始化一个新的工作空间,然后是要生成的特定子模块 mod 的参数。
命令如下:
项目结构如下:
生成的 go.work 文件的内容如下:
新的 go.work 与 go.mod 具有相同的语法,也可以与替换语法一起使用。
go.work 文件中总共支持三个指令。
go:声明 go 版本号,主要用于后续新语义的版本控制。
use:声明应用程序所依赖的模块的特定文件路径。该路径可以是绝对的或相对的,并且可以在应用程序的命运目录之外。
replace:声明模块依赖的导入路径被替换,优先于 go.mod 中的 replace 指令。
如果要禁用工作区模式,可以使用 -workfile=off 命令指定它。
即在运行时执行以下命令。
go.work 文件不需要提交到 Git 存储库,否则有点折腾。
只要您在 Go 项目中设置了 go.work,您将在运行时和编译时处于工作区模式,并且工作区配置将被给予最高优先级以满足您的本地开发需求。
工作区的核心知识到此结束。
如何创建工作区并使用
根据官方教程,我们来看一下如何使用多个工作区模式。
1、打开终端,进去 home 目录:
2、module 初始化
创建一个依赖于 http://golang.org/x/example 模块的新模块 hello:
3、使用 go get 添加对 http://golang.org/x/example 模块的依赖。
4、在 hello 目录下创建 hello.go 文件,内容如下:
最后的代码结构如下:
运行这个 hello 程序,得到一个反转的字符串结果:
5、我们将创建一个 go.work 文件来指定带有模块的工作区。
首先,初始化工作区:
go work init 命令告诉 go 为包含./hello 目录中的模块的工作空间创建一个 go.work 文件。go.work 文件的语法与 go.mod 相似
自动创建的 go.work 中的文件内容如下:
go 指令告诉 Go 应该使用哪个版本的 Go 来解释文件。它类似于 go.mod 文件中的 go 指令。
use 指令告诉 Go 在构建时 hello 目录中的模块应该是主模块。
因此,在工作区的任何子目录中,该模块都将处于活动状态。
然后,运行工作区目录下的程序
在工作区目录中,运行:
Go 命令包含工作区中的所有模块作为主模块。
这允许我们在模块中引用一个包,甚至在模块之外。在模块或工作区之外运行 go run 命令会导致错误,因为 go 命令不知道要使用哪些模块。
总结
今天我们介绍了 Go 1.18 的一个新特性:Multi-Module 工作空间模型。它本质上仍然是解决本地发展需求的一种解决方案。
由于 go.mod 文件与项目密切相关,因此它们基本上是上传到 Git 存储库的,因此很难对其进行任何操作。所以我们只是将 go.work 构建为纯本地化且易于使用。
使用新的 go.work,您可以处理完全的本地文件,而不会影响开发团队的其他成员。
更多关于多模块工作区的知识,可以查看官方的教程。
参考资料:
Go 1.18 is released!
New in Go 1.18: Multi-Module workspace mode
Go 1.18 新特性前瞻:Go 工作区模式
What are go workspaces and how do I use them?
Tutorial: Getting started with multi-module workspaces
版权声明: 本文为 InfoQ 作者【华为云开发者社区】的原创文章。
原文链接:【http://xie.infoq.cn/article/398622fd60fe7b99aa6fdd090】。文章转载请联系作者。
评论