这篇指导,介绍Go中基础的多模块工作空间。使用多模块工作空间。你能告诉Go命令,你将同时在多模块写代码,并且很容易在这些模块构建和运行代码。
在这篇指导中,你将用一个共享的多模块工作空间创建两个模块。跨越这些模块进行更改,并且在构建中看到这些结果的改变。
打开命令行,切换到工作目录
$ cd
$
创建一个叫workspace
的目录,并进入目录
$ mkdir workspace
$ cd workspace/
$
初始化那个模块
我们的例子中,将创建一个新的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
模块。
$ go get golang.org/x/example
go: downloading golang.org/x/example v0.0.0-20220412213650-2e68773dfca0
go: added golang.org/x/example v0.0.0-20220412213650-2e68773dfca0
$
在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
文件,看起来像这样:
$ ll
total 8
drwxr-xr-x 4 lifei staff 128 8 22 22:30 ./
drwxr-xr-x 6 lifei staff 192 8 22 22:18 ../
-rw-r--r-- 1 lifei staff 21 8 22 22:30 go.work
drwxr-xr-x 5 lifei staff 160 8 22 22:26 hello/
$ cat 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
模块在这一步,我们将下载一个Git仓库到拷贝,包含了golang.org/x/example
模块,添加它到工作空间。添加一个新的函数到它里面,然后我们在hello
程序中使用。
拷贝仓库
在workspace
目录下,运行git命令,拷贝仓库。
$ git clone https://go.googlesource.com/example
Cloning into 'example'...
remote: Total 204 (delta 93), reused 204 (delta 93)
Receiving objects: 100% (204/204), 103.24 KiB | 1006.00 KiB/s, done.
Resolving deltas: 100% (93/93), done.
$
添加模块到工作空间
$ go work use ./example
$
go work use
命令,添加一个新的模块到go.work
文件中。它看起来像这样:
$ cat go.work
go 1.18
use (
./example
./hello
)
$
这个模块,现在既包含了example.com/hello
模块,也包含了golang.org/x/example
模块。
这将允许我们使用新代码,我们将在stringutil
模块中写的,替换我们通过go get
命令下载,在模块缓存中的模块版本。
添加新函数
我们将添加一个新函数,去讲字符串变成大写,到golang.org/x/example/stringutil
包中。
在workspace/example/stringutil
目录中,创建一个文件名叫toupper.go
的文件,包含下面的内容:
package stringutil
import "unicode"
// 将参数中的所有字符转成大写
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.Reverse("Hello"))
fmt.Println(stringutil.ToUpper("Hello"))
}
在工作空间中运行代码:
$ 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 use [-r] [dir]
为 dir 的 go.work 文件添加一个 use 指令(如果存在),如果参数目录不存在,则删除 use 目录。-r
标志递归地检查 dir 的子目录。go work edit
编辑go.work
文件,类似go mod edit
go work sync
将工作区构建列表中的依赖项同步到每个工作区模块中。