Skip to content

Files

Latest commit

Mar 21, 2022
ab28946 · Mar 21, 2022

History

History

workspaces

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Mar 19, 2022
Mar 19, 2022
Mar 19, 2022
Mar 21, 2022
Mar 19, 2022
Mar 19, 2022

Go 1.18 新特性多模块工作区教程-让多模块开发变得简单

导读

  • 随着 2022 年 3 月 15 日 go 1.18 正式发布,新版本除了对性能的提升之外,还引入了很多新功能,其中就有 go 期盼已久的功能泛型(Generics),同时还引入的多模块工作区(Workspaces)和模糊测试(Fuzzing)。

  • 关于泛型网上已经有很多介绍的教程了,这里我介绍一个实用的功能,多模块工作区的使用方法和教程。

  • Go 多模块工作区能够使开发者能够更容易地同时处理多个模块的工作,如:

方便进行依赖的代码调试(打断点、修改代码)、排查依赖代码 bug
方便同时进行多个仓库/模块并行开发调试

目录

多模块工作区

说明

  • go 使用的是多模块工作区,可以让开发者更容易同时处理多个模块的开发。在 Go 1.17 之前,只能使用 go.mod replace 指令来实现,如果你正巧是同时进行多个模块的开发,使用它可能是很痛苦的。每次当你想要提交代码的时候,都不得不删除掉 go.mod 中的 replace 才能使模块稳定的发布版本。
  • 在使用 go 1.18 多模块工作区功能的时候,就使用这项工作变得简单容易处理。下面我来介绍怎么使用这一功能。
  • Go 多模块工作区文档、代码示例获取地址 https://github.com/link1st/link1st/tree/master/workspaces

使用条件

  • 首先 我们需要 go 1.18 或更高版本 go 安装
# 查看 go 版本
> go version
go version go1.18 darwin/amd64

go work 支持命令

  • 通常情况下,建议不要提交 go.work 文件到 git 上,因为它主要用于本地代码开发。

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

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

初始化并写入一个新的 go.work 到当前路径下,可以指定需要添加的代码模块
示例: go work init ./hello 将本地仓库 hello 添加到工作区
hello 仓库必须是 go mod 依赖管理的仓库(./hello/go.mod 文件必须存在)

  • go work use 添加新的模块到工作区

命令示例:
go work use ./example 添加一个模块到工作区
go work use ./example ./example1 添加多个模块到工作区
go work use -r ./example 递归 ./example 目录到当前工作区
删除命令使用 go work edit -dropuse=./example 功能

  • go work edit 用于编辑 go.work 文件

可以使用 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 从工作区中删除模块

  • go work sync 将工作区的构建列表同步到工作区的模块

  • go env GOWORK

查看环境变量,查看当前工作区文件路径 可以排查工作区文件是否设置正确,go.work 路径找不到可以使用 GOWORK 指定

> go env GOWORK
$GOPATH/src/link1st/link1st/workspaces/go.work

go.work 文件结构

  • 文件结构和 go.mod 文件结构类似,支持 Go 版本号、指定工作区和需要替换的仓库
  • 文件结构示例:
go 1.18

use (
    ./hello
    ./example
)

replace (
    github.com/link1st/example => ./example1
)

use 指定使用的模块目录
  • 可以使用 go work use hello 添加模块,也可以手动修改 go.work 工作区添加新的模块
  • 在工作区中添加了模块路径,编译的时候会自动使用 use 中的本地代码进行代码编译,和 replaces 功能类似。
# 单模块结构
use ./hello

# 多模块结构
use (
    ./hello
    ./example
)
replaces 替换依赖仓库地址
  • replaces 命令与 go.mod 指令相同,用于替换项目中依赖的仓库地址
  • 需要注意的是 replacesuse 不能同时指定相同的本地路径

同时指定报错信息:
go: workspace module github.com/link1st/example is replaced at all versions in the go.work file. To fix, remove the replacement from the go.work file or specify the version at which to replace the module.

  • 错误示例

同时在 usereplace 指定相同的本地路径

go 1.18

use (
    ./hello
    ./example
)

replace (
    github.com/link1st/example => ./example
)

go.work 文件优先级高于 go.mod 中定义
  • 在同时使用 go.workgo.mod replace 功能的的时候分别指定不同的代码仓库路径,go.work 优先级高于 go.mod 中定义

go.mod 中定义替换为本地仓库 example

replace (
    github.com/link1st/example => ./example1
)

go.work 中定义替换为本地仓库 example1

replace (
    github.com/link1st/example => ./example1
)
  • 在代码构建时候使用的是 go.work 指定的 example1 仓库的代码,go.work 优先级别更高

如何使用

  • 在 Go 1.18 go rungo build 都会默认使用工作区功能
  • GOWORK 也可以指定配置 go.work 文件位置
export GOWORK="~/go/src/test/go.18/workspace/go.work"

如何禁用工作区

  • Go 全局变量 GOWORK 设置 off 则可以禁用工作区功能

export GOWORK=off

开发流程演示

  • 演示如何使用多模块工作区功能。在现在微服务盛行的年代,一个人会维护多个代码仓库,很多的时候是多个仓库进行同时开发

  • 假设我们现在进行 hello 仓库开发,实现的功能是,实现将输入的字符串反转并输出,字符串反转功能依赖于 github.com/link1st/example (下文统称 example)公共仓库实现

  • 新建 hello 项目

mkdir hello
cd hello
# 代码仓库启动 go mod 依赖管理,生成 go.mod 文件
go mod init github.com/link1st/link1st/workspaces/hello
# 下载依赖包
go get github.com/link1st/example
# 编写 main 文件
vim main.go
  • main.go 代码
// Package main main 文件,go 多模块工作区演示代码
// 实现将输入的字符串反转输出并输出
package main

import (
    "flag"
    "fmt"

    "github.com/link1st/example/stringutil"
)

var (
    str = ""
)

func init() {
    flag.StringVar(&str, "str", str, "输入字符")
    flag.Parse()
}

func main() {
    if str == "" {
        fmt.Println("示例: go run main.go -str hello")
        fmt.Println("str 参数必填")
        flag.Usage()
        return
    }

    // 调用公共仓库,进行字符串反转
    str = stringutil.Reversal(str)
    // 输出反转后的字符串
    fmt.Println(str)
    return
}
  • 运行代码 go run main.go -str "hello world"go run github.com/link1st/link1st/workspaces/hello -str "hello world" 可以看到输出了 hello world 反转以后的字符串
> go run main.go -str "hello world"
dlrow olleh
  • 到这里,最初的功能已经完成,但是后续需求变动,不仅需要输出反转以后的字符串,还需要将字符串大写
  • 我们则需要去 example 仓库中添加开发 将字符串大写的功能
# 回到工作根目录,将 common 代码下载到本地进行添加新的功能
# 下载依赖的 example 包
git clone git@github.com:link1st/example.git
# 在 example 包中添加 字符串大学的功能

  • vim example/stringutil/to_upper.go 代码如下
// Package stringutil stringutil
package stringutil

import (
    "unicode"
)

// ToUpper 将字符串进行大写
func ToUpper(s string) string {
    r := []rune(s)
    for i := range r {
        r[i] = unicode.ToUpper(r[i])
    }
    return string(r)
}
  • 由于代码还在本地调试,未提交 git 仓库中,这个时候就需要用到 Go 多模块工作区的功能了。

  • 进入项目根目录,初始化我们现在正在开发的模块

# 初始化 go.work 文件
go work init  ./hello ./example
# 查看 go.work 文件内容
cat go.work
  • 文件结构如下
go 1.18

use (
    ./example
    ./hello
)
  • 回到 hello 项目,vim main.go 将字符串大写的功能添加上。
func main() {
    ...

    // 调用公共仓库,进行字符串反转
    str = stringutil.Reversal(str)
    // 增加字符大写的功能
    str = stringutil.ToUpper(str)
    // 输出反转后的字符串
    fmt.Println(str)
    
    ...
}
  • 运行代码

可以看到输出了反转并 大写 的字符串,大写的函数功能只在本地,未提交到 git 上,这样我们就实现了可以同时在两个模块上并行开发

go run main.go -str "hello world"
DLROW OLLEH
  • 到这里,演示的代码已经全部完成

总结

  • 使用 Go 多模块工作区的功能,可以让我们轻松在多个模块之间切换工作,更能适应现代微服务架构开发。

参考文献

Go 1.18 新特性多模块工作区教程

Go 1.18 is released!

Tutorial: Getting started with multi-module workspaces

go-1.18-features