01
介绍
Go 官方在 Go v1.11 新增 Go Modules 模式,并一直持续到 Go v1.16,每个版本的 Go Modules 模式都会有一些变化。但是,我们的项目使用 Go Modules 模式时,仍然会遇到一些问题。
直到 Go v1.18 版本新增 Workspaces 模式,解决了 Go Modules 模式的这些问题,本文我们介绍 Workspaces 模式的使用方式。
02
引言
当在项目中需要导入一些私有 Git 仓库或未发布到 Git 仓库的依赖项时,或需要修改三方依赖模块的代码时,一般解决方法是将代码下载到本地,在 go.mod
文件中使用 Go Modules 模式中的 replace
指令替换为本地目录路径。
因为 go.mod
文件也是和项目一起提交到 Git 仓库,每个开发人员的本地目录路径可能不一样,所以,就需要把在远程仓库拉取到的 go.mod
文件中 replace
的目录路径手动替换为自己的本地目录路径之后,才可以正常使用。
03
使用方式
在介绍 Workspaces 模式的使用方式之前,我们需要先使用 Go Modules 模式创建一个 Go 项目,并且我们的 Go 项目依赖模块 golang.org/x/example
。
创建 Go 项目
代码语言:javascript复制# 进入 Home 目录
cd ~
# 创建工作区目录
mkdir workspace
# 进入工作区目录
cd workspace
# 创建 Go 项目所在的目录
mkdir hello
# 进入 Go 项目所在的目录
cd hello
# 初始化
go mod init github.com/weirubo/hello
# 添加依赖项
go get golang.org/x/example
# 创建 main.go 文件
touch main.go
示例代码:
代码语言:javascript复制package main
import (
"fmt"
"golang.org/x/example/stringutil"
)
func main() {
str := "hello"
reverseStr := stringutil.Reverse(str)
fmt.Println(reverseStr)
}
输出结果:
代码语言:javascript复制go run main.go
olleh
阅读上面这段内容,是我们已经非常熟悉的使用 Go Modules 模式创建 Go 项目的操作步骤,接下来,我们介绍 Workspaces 模式的使用方式。
创建工作区
代码语言:javascript复制# 进入 Home 目录下的 workspace 目录
cd ~/workspace
# 初始化工作区
go work init ./hello
执行完以上命令,我们可以发现在 workspace 目录下创建了一个 go.work
文件,查看该文件,我们可以发现包含两个指令,分别是 go
和 use
。
go 1.19
use ./hello
其中 go
指令,是指定使用 Go 的哪个版本编译项目,类似 go.mod
文件中的 go
指令。
其中 use
指令,是指在构建项目时,hello
目录中的模块是主模块。
在创建工作区后,我们进入工作区目录,运行 main.go
文件。
cd ~/workspace
go run hello/main.go
输出结果:
代码语言:javascript复制olleh
但是,如果我们进入 Home
目录(工作区外),运行 main.go
文件。
cd ~
go run workspace/hello/main.go
输出结果:
代码语言:javascript复制workspace/hello/main.go:5:2: no required module provides package golang.org/x/example/stringutil: go.mod file not found in current directory or any parent directory; see 'go help modules'
我们可以在输出结果中发现,Go 找不到项目使用的依赖模块,原因是我们在工作区外运行 Go 项目,Go 找不到需要的模块。
04
使用场景
我们在学会使用 Workspaces 模式后,使用该模式解决 Part 02 提到的问题。
假如我们想要在 Go 项目的依赖模块 golang.org/x/example
新增一个函数 ToUpper
。
在 Go 未提供 Workspaces 模式时,我们需要下载依赖项到本地,然后修改下载到本地的依赖项文件。
代码语言:javascript复制cd ~/workspace/hello
git clone https://go.googlesource.com/example
# 编辑 go.mod
go mod edit -replace golang.org/x/example@v0.0.0-20220412213650-2e68773dfca0=/Users/frank/workspace/hello/example
此时,我们就可以修改我们下载到本地的依赖项文件 /Users/frank/workspace/hello/example/stringutil/reverse.go
,新增函数 ToUpper
。
func ToUpper(s string) string {
r := []rune(s)
for i := range r {
r[i] = unicode.ToUpper(r[i])
}
return string(r)
}
然后,我们可以在 main.go
文件中使用该函数。
...
toUpperStr := stringutil.ToUpper(str)
fmt.Println(toUpperStr)
...
输出结果:
代码语言:javascript复制cd ~/workspace/hello
go run main.go
HELLO
使用 Go Modules 模式的 replace
指令,虽然可以实现我们的需求,但是,当该项目代码在其他人电脑上运行时,必须先手动修改为自己的目录路径,才可以正常运行。
使用 Workspaces 模式
我们使用 Go 1.18 提供的 Workspaces 模式,实现我们的需求。
将下载到本地的依赖模块 example
添加到工作区:
cd ~/workspace
go work use ./hello/example
我们使用 go work use
命令将 example
模块添加到工作区,我们就可以使用我们下载到本地的依赖模块 example
的代码,而不再使用 GOMODCACHE
中的 example
模块的代码。
我们项目组成员只需维护自己本地的工作区,不必再手动修改 go.mod
文件中 replace
指令中的本地目录路径。
05
总结
本文我们先叙述使用 Go Modules 模式面临的一些问题,然后介绍 Go v1.18 新增的 Workspaces 模式的使用方式,最后通过示例介绍使用 Workspaces 模式可以解决使用 Go Modules 模式中的问题。
需要注意的是,go.work
文件不要推送到远程仓库,我们可以将其添加到 .gitignore
文件中。
我们在文中使用到的命令是 go work init
和 go work use
,此外,还有其他命令,感兴趣的读者朋友们可以执行命令 go help work
了解更多。
参考资料:
- https://github.com/golang/proposal/blob/master/design/45713-workspace.md
- https://www.youtube.com/watch?v=wQglU5aB5NQ
- https://go.dev/blog/get-familiar-with-workspaces
- https://go.dev/doc/tutorial/workspaces
- https://go.dev/ref/mod#workspaces
- https://pkg.go.dev/cmd/go#hdr-Workspace_maintenance
- https://go.dev/ref/mod#commands-outside