本文分享自华为云社区《一同看看 Go 1.18 新特性之多模块作业区形式》,作者:世界之一粟。

导言

2022年,Go 团队发布 Go 1.18 ,作为一个大的版别变化,Go 1.18 理所当然涵盖了许多的新功能、Go 团队也说到是 Go 语言发布以来做的最大的一次变化,而且性能改进很大。

其中一个功能,便是提供了一个多模块作业区的形式。官方博客说明如下:

Go 1.18 新特性:多模块工作区模式

该段文字的翻译:Go 模块简直已被遍及采用,Go 用户在咱们的年度查询报告中对 Go 模块给予十分高的满意度得分。在咱们的 2021 年用户查询中,用户跨多个模块作业识别出不同的模块最常见的应战。在 Go 1.18 中,咱们运用新的 Go 作业区形式处理了这个问题,这使得运用多个模块变得简略。

Go 的依靠办理,或 Go Module,已经存在了好几年,但一向受到许多批评和改进。在 Go 1.18 推出多模块作业区形式——Multi-Module Workspaces,用以支撑模块的多个作业空间,咱们来看看到底有什么特别。

先决条件

  • 装置 Go 1.18 或更高版别。
  • 用于编辑代码的东西。您具有的任何文本编辑器都能够正常作业。本文运用 VSCode。
  • 一个指令终端。 Go 在 Linux 和 Mac 上的任何终端以及 Windows 中的 PowerShell 或 cmd 上都能很好地作业。本文运用 Ubuntu

作业区形式

每天处理 Go 项目时,有两个经典问题特别无趣:

  • 依靠于本地 replace 模块
  • 依靠于本地未发布的模块。

replace module

第一种场景: 例如,在一个 Go 项目中,咱们会运用 replace 来处理一些本地依靠或自定义代码。咱们将在 go.mod 文件中运用 replace 来履行此操作。

如下的代码:

replace golang.org/x/net => /Users/eddycjy/go/awesomeProject

这在链接本地开发时答应准确性。可是一起又会有问题:

  • 本地途径:替换设置本质上转换为本地途径,这意味着每个人都是不同的。
  • 远程依靠:文件更改会上传到 Git 库房,所以假如你不小心上传了一个文件,会影响到其他开发者,或者每次上传都得改回来。

Unpublished modules

第二种场景: 当你在做一个本地的 Go 项目时,你可能一起在做多个库(项目库、东西库、第三方库)。

看如下的代码:

package main
import (
    "github.com/eddycjy/pkgutil"
)
func main() {
    pkgutil.PrintFish()
}

假如此刻运转 go rungo mod tidy,它将不起作用而且会失利。

将抛出如下过错。

fatal: repository 'https://github.com/eddycjy/pkgutil/' not found

此反常是由于库 github.com/eddycjy/pkgutil 在 GitHub 上不可用,因而无法拉取。

处理方案: 在 Go 1.18 之前,咱们要么替换,要么直接上传到 Github,依靠将由 Go 东西链拉取。

许多用户对此提出质疑:Go 的所有依靠项都必须上传到 GitHub,并具有强绑定吗?

这对新人十分不友好。

Workspace model

经过社区多轮反应,Michael Matloob 提出提案:Proposal: Multi-Module Workspaces in cmd/go,经过广泛讨论和施行,Go 1.18 正式施行。

新提案的中心概念之一是添加了 go work 作业空间概念,该概念针对 Go Module 依靠办理模型。

能够在本地项目的 go.work 文件中设置一系列依靠的模块本地途径,然后将途径下的模块组合成当前Go项目的作业空间,即 N 个 Go Modules into 1 Go Work,用作业空间具有最高的读取优先级。

咱们能够经过 go help 看到这一点,如下所示。

$ go help work
Work provides access to operations on workspaces.
Note that support for workspaces is built into many other commands, not
just 'go work'.
See 'go help modules' for information about Go's module system of which
workspaces are a part.
See https://go.dev/ref/mod#workspaces for an in-depth reference on
workspaces.
See https://go.dev/doc/tutorial/workspaces for an introductory
tutorial on workspaces.
A workspace is specified by a go.work file that specifies a set of
module directories with the "use" directive. These modules are used as
root modules by the go command for builds and related operations.  A
workspace that does not specify modules to be used cannot be used to do
builds from local modules.
go.work files are line-oriented. Each line holds a single directive,
made up of a keyword followed by arguments. For example:
	go 1.18
	use ../foo/bar
	use ./baz
	replace example.com/foo v1.2.3 => example.com/bar v1.4.5
The leading keyword can be factored out of adjacent lines to create a block,
like in Go imports.
	use (
	  ../foo/bar
	  ./baz
	)
The use directive specifies a module to be included in the workspace's
set of main modules. The argument to the use directive is the directory
containing the module's go.mod file.
The go directive specifies the version of Go the file was written at. It
is possible there may be future changes in the semantics of workspaces
that could be controlled by this version, but for now the version
specified has no effect.
The replace directive has the same syntax as the replace directive in a
go.mod file and takes precedence over replaces in go.mod files.  It is
primarily intended to override conflicting replaces in different workspace
modules.
To determine whether the go command is operating in workspace mode, use
the "go env GOWORK" command. This will specify the workspace file being
used.
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.

只需履行 go work init初始化一个新的作业空间,然后是要生成的特定子模块 mod 的参数。

指令如下:

go work init ./mod ./tools

项目结构如下:

awesomeProject
├── mod
│   ├── go.mod      // 子模块
│   └── main.go
├── go.work         // 作业区
└── tools
    ├── fish.go
    └── go.mod      // 子模块

生成的 go.work 文件的内容如下:

go 1.18
use (
    ./mod 
    ./tools
)

新的 go.workgo.mod 具有相同的语法,也能够与替换语法一同运用。

go 1.18
use (...)
replace golang.org/x/net => example.com/fork/net v1.4.5

go.work 文件中总共支撑三个指令。

  • go:声明 go 版别号,主要用于后续新语义的版别操控。
  • use:声明应用程序所依靠的模块的特定文件途径。该途径能够是肯定的或相对的,而且能够在应用程序的命运目录之外。
  • replace:声明模块依靠的导入途径被替换,优先于 go.mod 中的 replace 指令。

假如要禁用作业区形式,能够运用 -workfile=off 指令指定它。

即在运转时履行以下指令。

go run -workfile=off main.go
go build -workfile=off

go.work 文件不需要提交到 Git 存储库,不然有点折腾。

只需您在 Go 项目中设置了 go.work,您将在运转时和编译时处于作业区形式,而且作业区配置将被给予最高优先级以满足您的本地开发需求。

作业区的中心知识到此结束。

怎么创立作业区并运用

根据官方教程,咱们来看一下怎么运用多个作业区形式。

  1. 翻开终端,进去 home 目录:
$ cd
$ mkdir workspace_test && cd workspace_test
  1. module 初始化

创立一个依靠于 golang.org/x/example 模块的新模块 hello:

$ mkdir hello && cd hello
$ go mod init example.com/hello
go: creating new go.mod: module example.com/hello
  1. 运用 go get 添加对 golang.org/x/example 模块的依靠。
$ go get golang.org/x/example
go: downloading golang.org/x/example v0.0.0-20220304235025-ad95e7f791d8
go: added golang.org/x/example v0.0.0-20220304235025-ad95e7f791d8
  1. 在 hello 目录下创立 hello.go 文件,内容如下:
package main
import (
	"fmt"
	"golang.org/x/example/stringutil"
)
func main() {
	fmt.Println(stringutil.Reverse("Hello, yuzhou1su"))
}

最后的代码结构如下:

Go 1.18 新特性:多模块工作区模式

运转这个 hello 程序,得到一个回转的字符串成果:

$ go run example.com/hello
us1uohzuy ,olleH
  1. 咱们将创立一个 go.work 文件来指定带有模块的作业区。

首要,初始化作业区:

# wade @ wade-virtual-machine in ~/workspace_test [23:02:29]
$ go work init ./hello  

go work init 指令告知 go 为包括./hello 目录中的模块的作业空间创立一个 go.work 文件。go.work 文件的语法与 go.mod 类似

自动创立的 go.work 中的文件内容如下:

go 1.18
use ./hello
  • go 指令告知 Go 应该运用哪个版别的 Go 来解释文件。它类似于 go.mod 文件中的 go 指令。
  • use 指令告知 Go 在构建时 hello 目录中的模块应该是主模块。

因而,在作业区的任何子目录中,该模块都将处于活动状态。

然后,运转作业区目录下的程序

在作业区目录中,运转:

# wade @ wade-virtual-machine in ~/workspace_test [23:02:48]
$ go run example.com/hello
us1uohzuy ,olleH

Go 指令包括作业区中的所有模块作为主模块。

这答应咱们在模块中引证一个包,甚至在模块之外。在模块或作业区之外运转 go run 指令会导致过错,由于 go 指令不知道要运用哪些模块。

总结

今天咱们介绍了 Go 1.18 的一个新特性:Multi-Module 作业空间模型。它本质上仍然是处理本地发展需求的一种处理方案。

由于 go.mod 文件与项目密切相关,因而它们基本上是上传到 Git 存储库的,因而很难对其进行任何操作。所以咱们仅仅将 go.work 构建为纯本地化且易于运用。

运用新的 go.work,您能够处理完全的本地文件,而不会影响开发团队的其他成员。

更多关于多模块作业区的知识,能够检查官方的教程。

参考资料:

  • Go 1.18 is released!
  • New in Go 1.18: Multi-Module workspace mode
  • Go 1.18新特性前瞻:Go作业区形式
  • What are go workspaces and how do I use them?
  • Tutorial: Getting started with multi-module workspaces

点击关注,第一时间了解华为云新鲜技术~