摘要:在 Go 1.18 推出多模块工作区模式——Multi-Module Workspaces,用以支持模块的多个工作空间,我们来看看到底有什么特别。

本文分享自华为云社区《一起看看 Go 1.18 新特性之多模块工作区模式》,作者:宇宙之一粟 。

引言

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

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

https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/1a07c440990b40ebb01b897410ffcd69~tplv-k3u1fbpfcp-zoom-1.image

该段文字的翻译: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 run 或 go mod tidy,它将不起作用并且会失败。

将抛出如下错误。

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

此异常是因为库 http://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.work 与 go.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

2、module 初始化

创建一个依赖于 http://golang.org/x/example 模块的新模块 hello:

$ mkdir hello && cd hello
$ go mod init example.com/hello
go: creating new go.mod: module example.com/hello

3、使用 go get 添加对 http://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

4、在 hello 目录下创建 hello.go 文件,内容如下:

package main

import (
"fmt" "golang.org/x/example/stringutil"
) func main() {
fmt.Println(stringutil.Reverse("Hello, yuzhou1su"))
}

最后的代码结构如下:

https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/2af7a44539e948e396c965460fba4575~tplv-k3u1fbpfcp-zoom-1.image

运行这个 hello 程序,得到一个反转的字符串结果:

$ go run example.com/hello
us1uohzuy ,olleH

5、我们将创建一个 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

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

Go 1.18 新特性:多模块工作区模式的更多相关文章

  1. Java 18 新特性:使用Java代码启动jwebserver

    前几天分享了Java 18 新特性:简单Web服务器的jwebserver命令行功能. 今天换一种方式,使用Java代码来实现一个静态资源服务器. 详细步骤我录了个视频放到B站了,感兴趣的小伙伴可以点 ...

  2. Atitit.编程语言新特性 通过类库框架模式增强 提升草案 v3 q27

    Atitit.编程语言新特性 通过类库框架模式增强 提升草案 v3 q27 1. 修改历史2 2. 适用语言::几乎所有编程语言.语言提升的三个渠道::语法,类库,框架,ide2 2.1. 单根继承  ...

  3. Java 18 新特性:简单Web服务器 jwebserver

    在今年3月下旬的时候,Java版本已经更新到了18.接下来DD计划持续做一个系列,主要更新从Java 9开始的各种更新内容,但我不全部都介绍,主要挑一些有意思的内容,以文章和视频的方式来给大家介绍和学 ...

  4. CSS3和H5的新特性

    H5的新特性 1.   用于绘画 canvas 元素. 2.   用于媒介回放的 video 和 audio 元素. 3.   本地离线存储 localStorage 长期存储数据,浏览器关闭后数据不 ...

  5. ECMAscript6(ES6)新特性语法总结(一)

    ES6/ES2015,,在ES5的基础上扩展了很多新的功能,在使用的时候要慎重,因为有一部分js代码在部分浏览器是不兼容的,但是所有写在服务器端的代码基本上都支持ES6的写法. 新特性: 一.开启严格 ...

  6. 即将到来的Android N,将具备这些新特性

    原文转自:http://www.leiphone.com/news/201602/pSRQAuAjMFJITqHe.html         原创 訾竣喆 即将到来的Android N,将具备这些新特 ...

  7. 从开发者角度解析 Android N 新特性!

    大清早看到 Google 官方博客发布 Android N 的开发者预览版,立马从床上跳起来开始仔仔细细的读起来. 从开发者角度来看,Android N 的更新并不算大.网上之前流传的一些 Andro ...

  8. Atitit.atiJsBridge 新特性v7q329

    Atitit.atiJsBridge 新特性v7q329 atiJsBridge 未来计划 Postdata  图像上传的支持 Simp param计划 p1 p2 p3 p4 $method 的si ...

  9. Java知识回顾 (18)Java 8、9、11的新特性

    Java 8 Java 8 (又称为 jdk 1.8) 是 Java 语言开发的一个主要版本. Oracle 公司于 2014 年 3 月 18 日发布 Java 8 ,它支持函数式编程,新的 Jav ...

  10. atitit.TokenService v3 qb1  token服务模块的设计 新特性.docx

    atitit.TokenService v3 qb1  token服务模块的设计 新特性.docx 1.1. V3 新特性1 1.2. V2 新特性1 2. Token的归类1 3. Token的用途 ...

随机推荐

  1. 【虹科干货】Redis Enterprise vs ElastiCache——如何选择缓存解决方案?

    使用Redis 或 Amazon ElastiCache 来作为缓存加速已经是业界主流的解决方案,二者各有什么优势?又有哪些区别呢? 为了提高 Web 应用程序和数据驱动服务的性能与效率,使用 Red ...

  2. 数据结构与算法 | 二分搜索(Binary Search)

    二分搜索(Binary Search) 文承上篇,搜索算法中除了深度优先搜索(DFS)和广度优先搜索(BFS),二分搜索(Binary Search)也是最基础搜索算法之一. 二分搜索也被称为折半搜索 ...

  3. HTML DOM之三:节点关系导航

    1.获取节点列表 1 <!DOCTYPE html> 2 <html> 3 <body> 4 5 <p>Hello World!</p> 6 ...

  4. Error running 'TestAlterNickname.test': Command line is too long. Shorten command line for TestAlterNickname.test or also for JUnit default configuration

    问题描述 如图IDEA报错问题,发生在我用JUnit进行测试时. 解决方法 1. 直接点击 default 2. Modify options -> Shorten command line 3 ...

  5. mobaxterm软件的使用

    MobaXterm是一款功能强大的多功能远程计算机管理软件,可以在Windows操作系统下运行,支持SSH.Telnet.RDP.VNC等协议 一.软件下载与安装 下载地址:https://mobax ...

  6. 高效使用 PyMongo 进行 MongoDB 查询和插入操作

    插入到集合中: 要将记录(在MongoDB中称为文档)插入到集合中,使用insert_one()方法.insert_one()方法的第一个参数是一个包含文档中每个字段的名称和值的字典. import ...

  7. Verilog HDL数据流建模与运算符

    数据流建模使用的连续赋值语句由关键词assign开始,一般用法如下: wire [位宽说明]变量名1, 变量名2, ..., 变量名n; assign 变量名 = 表达式; 只要等号右边的值发生变化, ...

  8. Educational Codeforces Round 127 (Rated for Div. 2) E. Preorder

    设\(f[v]\)是以结点\(v\)为根的方案数,设左子树的根为\(x\),右子树的根为\(y\),那么如果左右子树完全相同,那么我们交换左右子树对方案没有任何影响,都是: \[f[v] = f[x] ...

  9. 基础练习:FJ的字符串

    问题描述 FJ在沙盘上写了这样一些字符串: A1 = "A" A2 = "ABA" A3 = "ABACABA" A4 = "AB ...

  10. python列表排序之sort(),sorted()和reverse()

    sort() 正序 sort()可以按字母的顺序来对列表进行永久性排序(改变列表自身的排序): list_1 = ['one', 'two', 'three', 'four', 'five'] pri ...