共计 3234 个字符,预计需要花费 9 分钟才能阅读完成。
背景
Go 1.18 除了引入泛型 (generics)、含糊测试(Fuzzing) 之外,另外一个重大性能是引入了工作区模式(workspace mode)。
工作区模式对 本地同时开发多个有依赖的 Module的场景十分有用。
举个例子,咱们当初有 2 个 Go module 我的项目处于开发阶段,其中一个是 example.com/main
,另外一个是example.com/util
。其中example.com/main
这个 module 须要应用 example.com/util
这个 module 里的函数。
咱们来看看 Go 1.18 版本前后如何解决这种场景。
Go 1.18 之前怎么做
在 Go 1.18 之前,对于上述场景有 2 个解决计划:
计划 1:被依赖的模块及时提交代码到代码仓库
这个计划很好了解,既然 example.com/main
这个 module 依赖了 example.com/util
这个 module,那为了 example.com/main
能应用到 example.com/util
的最新代码,须要做 2 个事件
- 本地开发过程中,如果
example.com/util
有批改,都马上提交代码到代码仓库,而后打 tag - 紧接着
example.com/main
更新依赖的example.com/util
的版本号 (tag),能够应用go get -u
命令。
这种计划比拟繁琐,每次 example.com/util
有批改,都要提交代码,否则 example.com/main
这个 module 就无奈应用到最新的example.com/util
。
计划 2:go.mod 里应用 replace 指令
为了解决方案 1 的痛点,于是有了计划 2:在 go.mod 里应用 replace 指令。
通过 replace 指令,咱们能够间接应用 example.com/util
这个 module 的本地最新代码,而不必把 example.com/util
的代码提交到代码仓库。
为了不便大家了解,咱们间接上代码。代码目录构造如下:
module
|
|------main
| |---main.go
| |---go.mod
|------util
| |---util.go
| |---go.mod
main 目录下的 main.go
代码如下:
//main.go
package main
import (
"fmt"
"example.com/util"
)
func main() {result := util.Add(1, 2)
fmt.Println(result)
}
main 目录下的 go.mod
内容如下:
module example.com/main
go 1.16
require example.com/util v1.0.0
replace example.com/util => ../util
util 目录下的 util.go
代码如下:
// util.go
package util
func Add(a int, b int) int {return a + b}
util 目录下的 go.mod
内容如下:
module example.com/util
go 1.16
这里最外围的是 example.com/main
这个 module 的go.mod
,最初一行应用了 replace 指令。
module example.com/main
go 1.16
require example.com/util v1.0.0
replace example.com/util => ../util
通过 replace 指令,应用 go 命令编译代码的时候,会找到本地的 util 目录,这样 example.com/main
就能够应用到本地最新的 example.com/util
代码。进入 main 目录,运行代码,后果如下所示:
$ cd main
$ go run main.go
3
然而这种计划也有个问题,咱们在提交 example.com/main
这个 module 的代码到代码仓库时,须要删除最初的 replace 指令,否则其余开发者下载后会编译报错,因为他们本地可能没有 util 目录,或者 util 目录的门路和你的不一样。
代码开源地址:Go 1.18 之前应用 replace 指令
Go 1.18 工作区模式
为了解决方案 2 的痛点,在 Go 1.18 里新增了工作区模式(workspace mode)。
该模式下不再须要在 go.mod
里应用 replace 指令,而是新增一个 go.work
文件。
话不多说,间接上代码。代码目录构造如下:
workspace
|------go.work
|
|------main
| |---main.go
| |---go.mod
|------util
| |---util.go
| |---go.mod
main 目录下的 main.go
代码如下:
//main.go
package main
import (
"fmt"
"example.com/util"
)
func main() {result := util.Add(1, 2)
fmt.Println(result)
}
main 目录下的 go.mod
内容如下:没有了计划 2 里最初一行的 replace 指令
module example.com/main
go 1.16
require example.com/util v1.0.0
util 目录下的 util.go
代码如下:
// util.go
package util
func Add(a int, b int) int {return a + b}
util 目录下的 go.mod
内容如下:
module example.com/util
go 1.16
go.work
内容如下:
go 1.18
use (
./main
./util
)
在 workspace 目录下执行如下命令即可主动生成go.work
$ go1.18beta1 work init main util
go1.18beta1 work init
前面跟的 main
和util
都是 Module 对应的目录。
如果 go 命令执行的当前目录或者父目录有 go.work
文件,或者通过 GOWORK
环境变量指定了 go.work
的门路,那 go 命令就会进入工作区模式。在工作区模式下,go 就能够通过 go.work
下的 module 门路找到并应用本地的 module 代码。
在 main 目录或者 workspace 目录,都能够运行main.go
,后果如下所示:
$ go1.18beta1 run main/main.go
3
$ cd main/
$ go1.18beta1 run main.go
3
这种模式下,咱们对 example.com/main
没有任何本地侵入性批改,不必像计划 2 那样,提交代码前还须要更新go.mod
文件。example.com/main
里的内容都能够间接提交到代码仓库。
代码开源地址:Go 1.18 工作区模式
留神 :go.work
不须要提交到代码仓库中,仅限于本地开发应用。
总结
为了解决多个有依赖的 Module 本地同时开发的问题,Go 1.18 引入了工作区模式。
工作区模式是对已有的 Go Module 开发模式的优化,对于工作区模式的更多细节能够参考本文最初的 References。
开源地址
文章和示例代码开源在 GitHub: Go 语言高级、中级和高级教程。
公众号:coding 进阶。关注公众号能够获取最新 Go 面试题和技术栈。
集体网站:Jincheng’s Blog。
知乎:无忌。
References
- Proposal 提案:https://go.googlesource.com/p…
- workspace 官网教程:https://go.dev/doc/tutorial/w…
- workspace 语法:https://go.dev/ref/mod#go-wor…
- go work 命令手册:https://pkg.go.dev/cmd/go@mas…
- go 1.18 release notes: https://tip.golang.org/doc/go…
- Go 如何援用本地 Module:https://github.com/jincheng9/…
- polarisxu: https://polarisxu.studygolang…