Go-17-工作区

问题背景

Golang 在1.18 推出了新特性 workspace 工作区模式

  1. 为什么要有 workspace
  2. 什么是 workspace
  3. 怎么使用 workspace

在工作过程中发现,模块的go.mod中添加了很多 replace,其实是为了解决依赖的问题。例如有2个module处于开发阶段,一个是example.com/web,一个是example.com/utilexample.com/web依赖example.com/util的函数,当两个模块同时开发过程中,为了 web 模块能够时候用到最新的 util 模块代码,有两种方案

方案1:就是将模块及时提交代码到代码仓库

  • 如果 util 有修改,那么就需要将代码提交到代码仓库,然后打上 tag
  • 然后使用 go get -u 更新 main 中依赖的 util 的版本号(tag)

缺点:每次需要提交代码并更新到最新

方案2:使用go.mod中使用replace指令,见代码

目录结构:

1
2
3
4
5
6
7
module
|-- web
| |-- go.mod
|-- main.go
|-- util
|-- go.mod
|-- util.go

文件web/web.go :

1
2
3
4
5
6
7
8
9
10
11
12
package main

import (
"fmt"

"example.com/util"
)

func main() {
result := util.Add(1, 2)
fmt.Println(result)
}

文件web/go.mod:

1
2
3
4
5
6
7
module example.com/web

go 1.18

require "example.com/util" v0.0.0

replace "example.com/util" => ../util

文件util/util.go:

1
2
3
4
5
package util

func Add(a int, b int) int {
return a + b
}

文件util/go.mod

1
2
3
module example.com/util

go 1.18

通过replace指令,使用go命令编译代码的时候,会找到本地的util目录,这样example.com/web就可以使用到本地最新的example.com/util代码

缺点:提交example.com/web这个module的代码到代码仓库时,需要删除最后的replace指令,否则其他开发者下载后会编译报错,因为他们本地可能没有util目录,或者util目录的路径和你的不一样

工作区

为了解决方案2的痛点,Go1.18 新增了工作区模式(workspace mode)

去掉 web/go.mod 中的 replace命令

1
2
3
4
5
module example.com/web

go 1.18

require "example.com/util" v0.0.0

在 web 模块中执行 go run hello.go,提示找不到依赖模块

1
2
hello.go:6:2: missing go.sum entry for module providing package example.com/util; to add:
go mod download example.com/util

使用 go work init web util指定工作模块 webutil,会生成 go.work 文件

1
2
3
4
5
6
go 1.18

use (
./util
./web
)

其中 use 用于表示需要指定的模块,再次执行 go run hello.go,则运行成功

目录结构

1
2
3
4
5
6
7
8
module
|-- go.work
|-- web
| |-- go.mod
|-- main.go
|-- util
|-- go.mod
|-- util.go

命令

1
2
3
4
5
6
7
8
9
10
11
root@13ce5bc74ac3:/code/module-workspace# go help work
Usage:
go work <command> [arguments]
The commands are:

edit edit go.work from tools or scripts
init initialize workspace file
sync sync workspace build list to modules
use add modules to workspace file

Use "go help work <command>" for more information about a command.
  1. 通常情况下,建议不要提交 go.work 文件到 git上,因为它主要用于本地代码开发

  2. 推荐在 $GOPATH 路径下执行,生成 go.work 文件

  3. go work init 初始化工作区文件,用于生成go.work工作区文件

  4. go work use 添加新的模块到工作区间

    1
    2
    3
    go work use ./example 添加一个模块到工作区
    go work use ./example ./example1 添加多个模块到工作区
    go work use -r ./example 递归 ./example 目录到当前工作区
  5. go work edit 用于编辑 go.work文件

    1
    2
    3
    4
    5
    6
    //可以使用 edit 命令编辑和手动编辑 go.work 文件效果是相同的 示例:
    go work edit -fmt go.work 重新格式化 go.work 文件
    go work edit -replace=github.com/link1st/example=./example go.work 替换代码模块
    go work edit -dropreplace=github.com/link1st/example 删除替换代码模块
    go work edit -use=./example go.work 添加新的模块到工作区
    go work edit -dropuse=./example go.work 从工作区中删除模块
  6. go work sync 将工作区的构建列表同步到工作区的模块

  7. go env GOWORK 查看环境变量,查看当前工作区文件路径 可以排查工作区文件是否设置正确,go.work 路径找不到可以使用 GOWORK 指定,生成多个go.work则指向最后一次生成的路径

  8. replace 指令的语法与 go.mod 中的 replace 指令相同,并优先于 go.mod 文件中的替换。这是主要用于覆盖不同工作区中的冲突替换模块

参考链接

  1. https://go.dev/blog/go1.18
  2. https://go.dev/doc/tutorial/workspaces
  3. https://tonybai.com/2021/11/12/go-workspace-mode-in-go-1-18/
  4. https://go.dev/ref/mod#workspaces