在使用 Golang 做编程的学习和工作中,经常会将一个项目拆分成多个模块,模块之间保持着一定层级的依赖关系。往往修改完上游模块后,必须发布以后,下游模块更新后才能使用修改后的上游模块,如果在下游模块使用时发现问题需要再次修改上游模块,然后再发布,下游模块再更新,如此往复,费时费力,大大降低开发和调试效率。

工作区(workspaces) 模式是 Go1.18 中引入的新功能,让多个模块并行开发和调试。无需在 go.mod 中使用 replace 来本地使用开发上游模块。

前言

在没有工作区之前,假设有两个模块mod1mod2mod1依赖mod2,如果mod2中做了修改,mod1要想使用mod2修改后的功能,有两种方式:

  1. 发布mod2git中,mod1使用go get github.com/project/mod2 更新依赖
  2. mod1中使用replace替换mod2的 git 仓库到本地目录,调试完成后,再移除 replace替换指令。

无论选择哪一种方式,都过于繁琐,特别是有多个模块同时开发时,下游模块无法和上游模块做到及时并行的开发和调试。

初始化工作区

工作区的操作命令是go work,其配置文件是go.work

先进入项目目录:

cd /project

在项目目录下初始化工作区:

go work init

初始化工作区,运行后会在工作区目录产生go.work文件,

添加模块到工作区

首先需要将项目的所有模块clone到工作区,假设该项目有三个模块:mod1mod2mod3mod1依赖mod2mod3

git clone github.com/project/mod1
git clone github.com/project/mod2
git clone github.com/project/mod3

将项目的这三个模块添加到工作区, 使用go work use ...可以一次性添加多个模块:

go work use mod1 mod2 mod3

执行完成后,这三个模块就添加到了工作区,go.work内容如下:

go 1.24.0

use (
    ./mod1
    ./mod2
    ./mod3
)

工作区目录结构

在上面完成工作区模块的添加后,整个工作区的目录结构如下:

$ tree
.
├── go.work
├── mod1
│   ├── go.mod
│   └── main.go
├── mod2
│   ├── go.mod
│   └── mod.go
└── mod3
    ├── go.mod
    └── mod.go

使用工作区以后,修改上游模块mod2 mod3 后,不需要发布,也不需要修改go.mod文件,在mod1中可以实时使用上游模块更新后的效果。

go run ./mod1

待所有模块同时开发和调试完成以后,就可以先发布上游模块,这时在mod1中使用go get更新所有上游模块即可。

go get github.com/project/mod2@v0.1.0
go get github.com/project/mod3@v0.1.0

最后

工作区模式可以说是Golang开发者的一个必备的利器,给多模块同时开发和调试带来了巨大的便利。

自 Go 1.18 以后,使用工作区模式,让开发者从传统的replace模式中彻底解放,从根本上解决了多模块开发的协作顽疾,让开发者更加专注于本地开发高效迭代。