Go 博客

熟悉工作区

Beth Brown,Go 团队
2022 年 4 月 5 日

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. 克隆您要编辑的上游模块。

  3. 将您的功能添加到上游模块的本地版本。

  4. 在工作区文件夹中运行 go work init [path-to-upstream-mod-dir]

  5. 修改您自己的模块以实现添加到上游模块的功能。

  6. 在工作区文件夹中运行 go work use [path-to-your-module]

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

    go 1.18
    
    use (
           ./path-to-upstream-mod-dir
           ./path-to-your-module
    )
    
  7. 使用添加到上游模块的新功能运行和测试您的模块。

  8. 发布包含新功能的上游模块。

  9. 发布使用新功能的模块。

在同一存储库中处理多个相互依赖的模块

在处理同一存储库中的多个模块时,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 文件的内容类似于以下内容

    go 1.18
    
    use (
            ./tools
            ./tools/groundhog
    )
    

    tools 模块中进行的任何本地更改都将在您的工作区中被 tools/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 work 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 版本、目录列表和替换列表。

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

go work init
go work sync
go work use
go list
go build
go test
go run
go vet

编辑器体验改进

我们对 Go 语言服务器 goplsVSCode Go 扩展 的升级感到特别兴奋,这些升级让在支持 LSP 的编辑器中使用多个模块变得轻松愉快。

在工作区内的模块之间查找引用、代码补全和跳转到定义。gopls0.8.1 版本 引入了对 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 文档

下一步是什么?

下一篇文章:何时使用泛型
上一篇文章:Go 如何缓解供应链攻击
博客索引