• 简体中文
  • 多模块工作区入门

    本教程介绍了 Go 中多模块工作区的基础知识。使用多模块工作区,你可以告诉 Go 命令你同时在多个模块中编写代码,并轻松构建和运行这些模块中的代码。

    在本教程中,你将在共享的多模块工作区中创建两个模块,在这些模块之间进行更改,并在构建中看到这些更改的结果。

    先决条件

    • 安装 Go 1.18 或更高版本。
    • 用于编辑代码的工具。 任何你拥有的文本编辑器都可以正常工作。
    • 命令终端。 Go 在 Linux 和 Mac 上的任何终端上都能很好地工作,在 Windows 上的 PowerShell 或 cmd 上也是如此。

    本教程需要 Go 1.18 或更高版本。请确保你已使用 go.dev/dl 中的链接安装了 Go 1.18 或更高版本。

    为代码创建模块

    首先,为要编写的代码创建一个模块。

    1. 打开命令提示符并切换到你的主目录。

      在 Linux 或 Mac 上:

      $ cd

      在 Windows 上:

      C:\> cd %HOMEPATH%

      本教程的其余部分将显示 $ 作为提示符。你使用的命令在 Windows 上也能工作。

    2. 从命令提示符,创建一个名为 workspace 的代码目录。

      $ mkdir workspace
      $ cd workspace
    3. 初始化模块

      我们的示例将创建一个新的模块 hello,它将依赖于 golang.org/x/example 模块。

      创建 hello 模块:

      $ mkdir hello
      $ cd hello
      $ go mod init example.com/hello
      go: creating new go.mod: module example.com/hello

      通过使用 go get 添加对 golang.org/x/example/hello/reverse 包的依赖。

      $ go get golang.org/x/example/hello/reverse

      在 hello 目录中创建 hello.go,内容如下:

      package main
      
      import (
          "fmt"
      
          "golang.org/x/example/hello/reverse"
      )
      
      func main() {
          fmt.Println(reverse.String("Hello"))
      }

      现在,运行 hello 程序:

      $ go run .
      olleH

    创建工作区

    在此步骤中,我们将创建一个 go.work 文件来指定包含模块的工作区。

    初始化工作区

    workspace 目录中,运行:

    $ go work init ./hello

    go work init 命令告诉 go 为包含 ./hello 目录中模块的工作区创建 go.work 文件。

    go 命令生成一个 go.work 文件,看起来像这样:

    go 1.18
    
    use ./hello

    go.work 文件的语法与 go.mod 类似。

    go 指令告诉 Go 应使用哪个版本的 Go 来解释该文件。它与 go.mod 文件中的 go 指令类似。

    use 指令告诉 Go,在构建时,hello 目录中的模块应该是主模块。

    因此,在 workspace 的任何子目录中,该模块都将是活动的。

    在工作区目录中运行程序

    workspace 目录中,运行:

    $ go run ./hello
    olleH

    Go 命令包括工作区中的所有模块作为主模块。这允许我们引用模块中的包,即使在模块之外也可以。在模块或工作区之外运行 go run 命令会导致错误,因为 go 命令不知道要使用哪些模块。

    接下来,我们将把 golang.org/x/example/hello 模块的本地副本添加到工作区。该模块存储在 go.googlesource.com/example Git 仓库的子目录中。然后,我们将向 reverse 包添加一个新函数,我们可以从 hello 程序中使用它来代替 String

    下载并修改 golang.org/x/example/hello 模块

    在此步骤中,我们将下载包含 golang.org/x/example/hello 模块的 Git 仓库副本,将其添加到工作区,然后向其添加一个新函数,我们可以在 hello 程序中使用它。

    1. 克隆仓库

      从 workspace 目录运行 git 命令以克隆仓库:

      $ git clone https://go.googlesource.com/example
      Cloning into 'example'...
      remote: Total 165 (delta 27), reused 165 (delta 27)
      Receiving objects: 100% (165/165), 434.18 KiB | 1022.00 KiB/s, done.
      Resolving deltas: 100% (27/27), done.
    2. 将模块添加到工作区

      Git 仓库刚刚被检出到 ./examplegolang.org/x/example/hello 模块的源代码在 ./example/hello。 将其添加到工作区:

      $ go work use ./example/hello

      go work use 命令向 go.work 文件添加新模块。它现在看起来像这样:

      go 1.18
      
      use (
          ./hello
          ./example/hello
      )

      工作区现在包括 example.com/hello 模块和提供 golang.org/x/example/hello/reverse 包的 golang.org/x/example/hello 模块。

      这将允许我们使用我们将在 reverse 包的副本中编写的新代码,而不是使用我们在 go get 命令下载的模块缓存中的包版本。

    3. 添加新函数。

      我们将向 golang.org/x/example/hello/reverse 包添加一个新函数来反转数字。

      workspace/example/hello/reverse 目录中创建一个名为 int.go 的新文件,内容如下:

      package reverse
      
      import "strconv"
      
      // Int 返回整数 i 的十进制反转。
      func Int(i int) int {
          i, _ = strconv.Atoi(String(strconv.Itoa(i)))
          return i
      }
    4. 修改 hello 程序以使用该函数。

      修改 workspace/hello/hello.go 的内容,使其包含以下内容:

      package main
      
      import (
          "fmt"
      
          "golang.org/x/example/hello/reverse"
      )
      
      func main() {
          fmt.Println(reverse.String("Hello"), reverse.Int(24601))
      }

    在工作区中运行代码

    从 workspace 目录运行

    $ go run ./hello
    olleH 10642

    Go 命令在命令行中指定的 example.com/hello 模块在 go.work 文件指定的 hello 目录中找到,并类似地使用 go.work 文件解析 golang.org/x/example/hello/reverse 导入。

    可以使用 go.work 而不是添加 replace 指令来跨多个模块工作。

    由于两个模块在同一个工作区中,在一个模块中进行更改并在另一个模块中使用它非常容易。

    后续步骤

    现在,为了正确发布这些模块,我们需要为 golang.org/x/example/hello 模块进行发布,例如发布为 v0.1.0。这通常通过在模块的版本控制仓库上标记提交来完成。有关更多详细信息,请参阅 模块发布工作流文档。一旦发布完成,我们可以在 hello/go.mod 中增加对 golang.org/x/example/hello 模块的要求:

    cd hello
    go get golang.org/x/example/hello@v0.1.0

    这样,go 命令可以在工作区外正确解析模块。

    了解有关工作区的更多信息

    除了我们之前在本教程中看到的 go work init 外,go 命令还有几个用于处理工作区的子命令:

    • go work use [-r] [dir]go.work 文件添加一个 use 指令以指向 dir,如果它存在,并且如果参数目录不存在,则删除 use 目录。-r 标志递归地检查 dir 的子目录。
    • go work edit 类似于 go mod edit,编辑 go.work 文件
    • go work sync 将工作区的构建列表中的依赖项同步到每个工作区模块中。

    有关工作区和 go.work 文件的更多详细信息,请参阅 Go 模块参考中的 工作区