熟悉工作区

Beth Brown, for the Go team 5 April 2022

Go 1.18为Go增加了工作区模式,使你可以同时在多个模块上工作。

你可以通过访问下载页面获得Go 1.18。发布说明有关于所有变化的更多细节。

工作区

Go 1.18中的工作区可以让你同时处理多个模块,而不必为每个模块编辑go.mod文件。在解决依赖关系时,工作区中的每个模块都被视为根模块。

以前,如果要在一个模块中增加一个功能,并在另一个模块中使用,你需要在第一个模块中发布修改,或者编辑依赖模块的go.mod文件,为你的本地未发布的模块变化添加replace指令。为了不出错地发布,你必须在向第一个模块发布本地修改后,从依赖模块的go.mod文件中删除replace指令。

通过Go工作区,你可以使用工作区目录根部的go.work文件来控制所有的依赖关系。go.work文件有usereplace指令,可以覆盖各个go.mod文件,所以不需要单独编辑每个go.mod文件。

你可以通过运行go work init来创建一个工作区,并将模块目录列表作为空格分隔的参数。工作区不需要包含你正在使用的模块。init命令创建一个go.work文件,列出工作区的模块。如果你在运行go work init时没有参数,该命令会创建一个空的工作区。

要向工作区添加模块,可以运行go work use [moddir] 或手动编辑go.work文件。运行go work use -r来递归添加参数目录中带有go.mod文件的目录到你的工作区。如果一个目录没有go.mod文件,或者不再存在,使用use指令的目录将会从go.work文件中删除。

go.work文件的语法与go.mod文件相似,包含以下指令:

  • go:go工具链的版本,例如:go 1.18
  • use:将磁盘上的一个模块添加到工作区的主模块集合中。它的参数是包含该模块go.mod文件的目录的相对路径。use指令不会在指定目录的子目录中添加模块。
  • replace: 与go.mod文件中的replace指令类似,go.work文件中的replace指令用其他地方的内容替换一个模块的特定版本所有版本

工作流

工作区是灵活的,支持各种工作流程。以下部分是对我们认为最常见的工作区使用的简要概述。

在上游模块中增加一个功能,并在自己的模块中使用它

  1. 为你的工作区创建一个目录。
  2. 克隆你要编辑的上游模块。如果你以前没有为Go贡献过,请阅读贡献指南
  3. 将你的功能添加到上游模块的本地版本中。
  4. 在工作区文件夹中运行go work init [path-to-upstream-mod-dir]
  5. 对你自己的模块进行修改,以实现添加到上游模块的功能。
  6. 在工作区文件夹中运行go work use [path-to-your-module]

    go work use命令将模块的路径添加到你的go.work文件中:

  1. go 1.18
  2. use (
  3. ./path-to-upstream-mod-dir
  4. ./path-to-your-module
  5. )
  1. 使用添加到上游模块的新功能运行并测试你的模块。
  2. 发布带有新功能的上游模块。
  3. 使用新功能发布你的模块。

在同一个资源库中与多个相互依赖的模块一起工作

在同一版本库中处理多个模块时,go.work文件定义了工作区,而不是在每个模块的go.mod文件中使用replace指令。

  1. 为你的工作区创建一个目录。

  2. 克隆你想编辑的模块的版本库。这些模块不一定要在你的工作区文件夹中,因为你可以用use指令指定每个模块的相对路径。

  3. 在你的工作区目录下运行go work init [path-to-module-one] [path-to-module-two]

    例子。你正在开发example.com/x/tools/groundhog,它依赖于example.com/x/tools模块中的其他软件包。

    你克隆了软件库,然后在你的工作区文件夹中运行go work init tools tools/groundhog

    你的go.work文件的内容类似于以下内容:

    1. go 1.18
    2. use (
    3. ./tools
    4. ./tools/groundhog
    5. )

    tool模块中做出的任何本地修改都将被你的工作区中的tool/groundhog所使用。

在依赖性配置之间进行切换

为了用不同的依赖配置测试你的模块,你可以用独立的go.work文件创建多个工作区,或者保留一个工作区,在一个go.work文件中注释掉你不需要的use指令。

要创建多个工作区。

  1. 为不同的依赖性需求创建单独的目录。
  2. 在每个工作区的目录中运行go work init
  3. 通过 “go work use [path-to-dependency]”在每个目录中添加你想要的依赖性。
  4. 在每个工作区目录中运行go run [path-to-your-module],以使用其go.work文件所指定的依赖项。

要在同一工作区测试不同的依赖关系,请打开go.work文件,添加或注释所需的依赖关系。

还在使用GOPATH吗?

也许使用工作区会改变你的想法。GOPATH用户可以使用位于其GOPATH目录底部的go.work文件来解决他们的依赖关系。工作区的目的不是要完全重新创建所有的GOPATH工作流程,但它们可以创建一个设置,分享GOPATH的一些便利,同时仍然提供模块的好处。

要为GOPATH创建一个工作区:

  1. 在你的GOPATH目录下运行go work init
  2. 要在你的工作区中使用一个本地模块或特定版本作为依赖,运行go work use [path-to-module]
  3. 要替换你的模块的go.mod文件中的现有依赖关系,请使用go work replace [path-to-module]
  4. 要添加你的GOPATH或任何目录中的所有模块,运行go work use -r来递归地添加有go.mod文件的目录到你的工作区。如果一个目录没有go.mod文件,或者不再存在,使用use指令的目录将会从 go.work文件中删除。

注意:如果你有没有go.mod文件的项目,你想把它添加到工作区,请换到它们的项目目录,运行go mod init,然后用go work use [path-to-module]把新模块添加到你的工作区。

工作区指令

除了go work initgo use之外,Go 1.18为工作区引入了以下命令:

  • go work sync:将go.work文件中的依赖关系推回到每个工作区模块的go.mod文件中。
  • go work edit:为编辑go.work提供一个命令行接口,主要供工具或脚本使用。

模块感知的构建命令和一些 go mod子命令会检查 GOWORK环境变量,以确定它们是否处于工作区环境中。

如果GOWORK变量命名的文件路径以.work结尾,则工作区模式被激活。要确定哪个go.work文件正在被使用,请运行go env GOWORK。如果go命令不在工作区模式下,则输出为空。

当工作区模式被启用时,go.work文件被解析以确定工作区模式的三个参数:一个Go版本,一个目录列表,以及一个替换列表。

在工作区模式下可以尝试一些命令(前提是你已经知道它们的作用!):

  1. go work init
  2. go work sync
  3. go work use
  4. go list
  5. go build
  6. go test
  7. go run
  8. go vet

编辑器体验的改进

我们对Go语言服务器goplsVSCode Go扩展的升级感到特别兴奋,这使得在兼容LSP的编辑器中处理多个模块的工作变得顺利而有意义。

查找引用、代码补全和转到定义在工作区中跨模块工作。版本0.8.1gopls引入了诊断、完成、格式化和对go.work文件的悬停。你可以用任何LSP兼容的编辑器来利用这些gopls的功能。

编辑的具体说明

  • 最新的vscode-go版本允许通过Go状态栏的快速选择菜单快速访问你的工作区的go.work文件。

Access the go.work file via the Go status bar’s Quick Pick menu

  • GoLand支持工作区,并计划为go.work文件增加语法高亮和代码完成。

关于在不同编辑器中使用gopls的更多信息,请看gopls文档

接下来是什么?