Go 1.20要来了,看看都有哪些变化-第2篇
Contents
前言
Go官方团队在2022.12.08发布了Go 1.20 rc1(release candidate)版本,Go 1.20的正式release版本预计会在2023年2月份发布。
让我们先睹为快,看看Go 1.20给我们带来了哪些变化。
安装方法:
|
|
这是Go 1.20版本更新内容详解的第2篇,欢迎大家关注公众号,及时获取本系列最新更新。
第1篇主要涉及Go 1.20在语言、可移植性方面的优化,原文链接:Go 1.20版本升级内容第1篇。
Go 1.20发布清单
和Go 1.19相比,改动内容适中,主要涉及语言(Language)、可移植性(Ports)、工具链(Go Tools)、运行时(Runtime)、编译器(Compiler)、汇编器(Assembler)、链接器(Linker)和核心库(Core library)等方面的优化。
本文重点介绍Go 1.20在Go工具链方面的优化。
Go command
$GOROOT/pkg
路径不再存储标准库源代码编译后生成的文件,包括以下几点:
go install
不再往$GOROOT/pkg
目录写文件。go build
不再检查$GOROOT/pkg
下的文件。- Go发布包不再带有这些编译文件。
以macOS环境来演示:在Go 1.16版本里,$GOROOT/pkg
目录下的内容如下:
|
|
但是在Go 1.20rc1版本里,$GOROOT/pkg
目录下的内容如下:
|
|
少了darwin_amd64
和darwin_amd64_race
这2个文件夹:
|
|
从Go 1.20开始,标准库的package会按需编译,编译后生成的文件会缓存在编译缓存(build cache)里,就像非GOROOT
下的package一样。这个修改减小了Go安装包的大小。
go test -json
的实现在Go 1.20版本更加鲁棒,对使用go test -json
的开发者来说,不用做任何改变。
但是,直接调用Go工具test2json
的开发者,需要给测试的可执行程序增加-v=test2json
参数,例如go test -v=test2json
或者./pkg.test -test.v=test2json
,而不是仅仅加一个-v
标记。
go test -json
的另外一个修改是在每个测试程序执行的开始,增加了一个Action
事件。当使用go命令同时运行多个测试程序时,这些Action
事件的执行会按照命令行里的package的顺序按序执行。
go
命令现在新增了和CPU架构相关的编译标记参数,例如amd64.v2
。有了这个参数后,在业务代码实现的时候就可以根据CPU架构的不同而做不同的处理。更多细节可以参考:go help buildconstraint
。
go
子命令现在支持-C <dir>
参数,可以在执行命令前改变目录到<dir>
下。如果一个脚本要在多个不同的Go module下执行,这个特性会带来方便。
go
build
和 go
test
命令不再支持-i
参数,这个参数从 Go 1.16版本开始弃用。
go generate
命令接受 -skip <pattern>
参数,可以跳过匹配 <pattern>
格式的 //go:generate
指令。
go test
命令接受-skip <pattern>
参数,可以跳过匹配 <pattern>
格式的测试用例。
go build
, go install
和其它编译相关的命令新增了一个-pgo
标记参数,可以辅助开发者做程序优化。-pgo
指定的是profile文件的路径。如果-pgo=auto
,那go命令会在main这个包的路径下去找名为default.pgo
的文件。-pgo=off
可以关闭优化。详情可以参考:PGO Proposal。
go build
, go install
和其他编译相关的命令新增了一个-cover
标记参数,可以用来对编译出来的可执行程序做代码覆盖率收集,详情可以参考本文后面介绍。
go version
go version -m
命令支持读取和解析更多类型的Go二进制文件。
比如通过go build -buildmode=c-share
编译出来的Windows DLL文件以及没有可执行权限的Linux二进制文件,现在都可以被go version -m
解析和识别到。
Cgo
早期Go语言的一些标准库是用C语言实现的,需要依赖cgo来作为go语言和C语言的桥梁。
现在Go语言开始去除对C语言的的依赖。
从Go 1.20版本开始,如果机器上没有C语言的工具链,go命令会默认禁用cgo
。
具体而言:如果没有设置CGO_ENABLED
和CC
环境变量,而且默认的C语言编译器(例如clang
和gcc
)也找不到,那CGO_ENABLED
会默认为0。当然开发者可以通过设置CGO_ENABLED
环境变量的值来改变CGO_ENABLED
的值。
这个修改会让Go语言减少对C语言工具链的依赖,适配更多的环境,尤其是最小化的容器环境以及macOS环境。
Go标准库里使用了cgo的package有: net
, os/user
和 plugin
。
在macOS环境,net
和os/user
包已经被重写了,不再依赖cgo。现在net
和os/user
的代码实现既可以用cgo编译,也可以不用cgo编译。同时,在macOS环境,race detector已经被重写了,不再依赖cgo。
在Windows环境,net
和os/user
没有使用过cgo。
在其它操作系统上,如果编译的时候禁用了cgo,那会使用这些包的纯go语言实现。
在macOS环境,race detector已经被重写了,不再依赖cgo。
Cover(代码覆盖率检测)
Go 1.20版本之前只支持对单元测试(unit test)收集代码覆盖率,从Go 1.20版本开始支持对任何Go程序做代码覆盖率收集。
那如何收集呢?需要做如下操作:
- 给
go build
编译命令增加-cover
标记 - 给环境变量
GOCOVERDIR
赋值为某个路径 - 运行
go build
编译出来的可执行程序时,会把代码覆盖率文件输出到GOCOVERDIR
指定的路径下。
详细的介绍文档和使用说明可以参考: coverage for integration tests' landing page 。
想了解设计原理和实现的可以参考: proposal。
Vet
检测循环变量被嵌套子函数错误使用的场景
|
|
大家可以猜一下这段程序里t.Log打印的结果是什么?结果是为1,2,3,4还是4,4,4,4?是否和自己的预期相符。
想了解详情的可以参考:Be Careful with Table Driven Tests and t.Parallel()。
这个本质上和goroutine与闭包函数一起使用时,遇到的循环变量问题一样。
Go 1.20版本开始通过go vet
可以检测出单元测试里的这类问题。
检查错误时间格式
对于 Time.Format
和time.Parse
,如果代码里要转成yyyy-dd-mm的格式,会给出提示。
因为yyyy-dd-mm不符合常用的日期格式标准,ISO 8601日期格式是yyyy-mm-dd格式。
总结
下一篇会介绍Go 1.20在运行时、编译器、汇编器、链接器和核心库的优化工作,有一些内容值得学习,欢迎大家保持关注。
推荐阅读
开源地址
文章和示例代码开源在GitHub: Go语言初级、中级和高级教程。
公众号:coding进阶。关注公众号可以获取最新Go面试题和技术栈。
个人网站:Jincheng’s Blog。
知乎:无忌。
福利
我为大家整理了一份后端开发学习资料礼包,包含编程语言入门到进阶知识(Go、C++、Python)、后端开发技术栈、面试题等。
关注公众号「coding进阶」,发送消息 backend 领取资料礼包,这份资料会不定期更新,加入我觉得有价值的资料。还可以发送消息「进群」,和同行一起交流学习,答疑解惑。