多模块工作区
使用多模块工作区,告诉 Go 命令您正在同时在多个模块中编写代码,并轻松地在这些模块中构建和运行代码。
在本教程中,您将在共享的多模块工作区中创建两个模块,对这些模块进行更改,并在构建中查看这些更改的结果。
本教程需要 go 1.18 或更高版本。
创建一个模块
-
打开命令提示符并切换到您的主目录,为您的代码创建一个名为工作区的目录。
$ mkdir workspace $ cd workspace
-
初始化模块
创建一个依赖于
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
模块的依赖项。$ go get golang.org/x/example
-
在 hello 目录下创建 hello.go,内容如下:
package main import ( "fmt" "golang.org/x/example/stringutil" ) func main() { fmt.Println(stringutil.Reverse("Hello")) }
-
运行hello程序:
$ go run example.com/hello 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 example.com/hello olleH
Go 命令包括工作区中的所有模块作为主模块。这允许我们在模块中引用一个包,甚至在模块之外。在模块或工作区之外运行
go run
命令会导致错误,因为该go
命令不知道要使用哪些模块。接下来,我们将
golang.org/x/example
模块的本地副本添加到工作区。然后,我们将向stringutil
包中添加一个新函数,我们可以使用它来代替Reverse
.
下载和修改golang.org/x/example
模块
在这一步中,我们将下载包含golang.org/x/example
模块的 Git 存储库的副本,将其添加到工作区,然后向其中添加一个我们将从 hello 程序中使用的新函数。
-
克隆存储库
在 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.
-
将
example
模块添加到工作区$ go work use ./example
该
go work use
命令将一个新模块添加到 go.work 文件中。它现在看起来像这样:go 1.18 use ( ./hello ./example )
模块现在包括
example.com/hello
模块和golang.org/x/example
模块。这将允许我们使用我们将在
stringutil
模块副本中编写的新代码,而不是使用命令go get
下载的模块缓存中的模块版本。 -
添加新函数
我们将向
golang.org/x/example/stringutil
包中添加一个新函数以将字符串大写。在目录
workspace/example/stringutil
中创建一个名为toupper.go
的新文件,包含以下内容:package stringutil import "unicode" // ToUpper uppercases all the runes in its argument string. func ToUpper(s string) string { r := []rune(s) for i := range r { r[i] = unicode.ToUpper(r[i]) } return string(r) }
-
修改hello程序以使用该函数。
修改
workspace/hello/hello.go
文件,内容如下:package main import ( "fmt" "golang.org/x/example/stringutil" ) func main() { fmt.Println(stringutil.ToUpper("Hello")) }
-
在workspace目录下,运行代码
$ go run example.com/hello HELLO
Go 命令在文件
go.work
指定的目录hello
中查找命令行中指定的模块example.com/hello
,同样使用文件go.work
解析导入golang.org/x/example
。go.work
可以用来代替添加replace
指令以跨多个模块工作。由于这两个模块在同一个工作区中,因此很容易在一个模块中进行更改并在另一个模块中使用它。
-
未来的一步
现在,要正确发布这些模块,我们需要发布
golang.org/x/example
模块,例如在v0.1.0
。这通常通过在模块的版本控制存储库上标记提交来完成。有关更多详细信息,请参阅 模块发布工作流程文档 。发布完成后,我们可以在hello/go.mod
中增加对golang.org/x/example
模块的要求:cd hello go get golang.org/x/example@v0.1.0
这样,该go命令可以正确解析工作区之外的模块。
了解有关工作区的更多信息
除了我们在教程前面看到的go work init
之外,go命令还有几个用于处理工作区的子命令:
go work use [-r] [dir]
如果目录dir
存在,则将use
指令添加到文件go.work
中,如果参数目录不存在,则删除该use
目录。标志-r
递归地检查dir
子目录。go work edit
编辑go.work
文件类似于go mod edit
go work sync
将工作区构建列表中的依赖项同步到每个工作区模块中。
有关workspaces(工作区)和go.work
文件的更多详细信息,请参阅 Go Modules Reference 中的 Workspaces。