Go 博客

熟悉工作区

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

Go 1.18 向 Go 添加了工作区模式,允许您同时处理多个模块。

您可以通过访问下载页面获取 Go 1.18。发行说明中提供了所有更改的更多详细信息。

工作区

Go 1.18 中的工作区允许您同时处理多个模块,而无需为每个模块编辑 go.mod 文件。工作区内的每个模块在解决依赖关系时都被视为主要模块。

以前,要在某个模块中添加一个特性并在另一个模块中使用它,您需要发布第一个模块的更改,或者使用 replace 指令编辑依赖模块的 go.mod 文件,指向您本地未发布的模块更改。为了在发布时不出错,您必须在将本地更改发布到第一个模块后,从依赖模块的 go.mod 文件中移除 replace 指令。

使用 Go 工作区,您可以在工作区目录的根目录下使用 go.work 文件控制所有依赖关系。go.work 文件具有覆盖单个 go.mod 文件的 usereplace 指令,因此无需单独编辑每个 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 的编辑器中处理多个模块成为一种顺畅且有益的体验。

查找引用、代码补全和跳转到定义在工作区内的模块之间正常工作。版本 0.8.1gopls 引入了针对 go.work 文件的诊断、补全、格式化和悬停功能。您可以在任何 LSP 兼容的编辑器中利用这些 gopls 特性。

编辑器特定说明

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

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

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

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

下一步?

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