前言
Go官方团队在2022.06.11发布了Go 1.19 Beta 1版本,Go 1.19的正式release版本预计会在今年8月份发布。
让我们先睹为快,看看Go 1.19给我们带来了哪些变化。
这是Go 1.19版本更新内容详解的第4篇,欢迎大家关注公众号,及时获取本系列最新更新。
第1篇主要涉及Go泛型的改动、Go内存模型和原子操作的优化,原文链接:Go 1.19版本变更内容第1篇。
第2篇主要涉及Go文档注释(doc comments)、编译约束(build constraint)以及Go命令的修改,原文链接:Go 1.19版本变更内容第2篇。
第3篇主要涉及Go运行时、编译器、汇编器和链接器方面的改动和优化,原文链接:Go 1.19版本变更内容第3篇。
Go 1.19发布清单
和Go 1.18相比,改动相对较小,主要涉及语言(Language)、内存模型(Memory Model)、可移植性(Ports)、Go Tool工具链、运行时(Runtime)、编译器(Compiler)、汇编器(Assembler)、链接器(Linker)和核心库(Core library)等方面的优化。
本文重点介绍Go 1.19版本在核心库(Core library)方面的变化。
新的原子类型(New atomic types)
sync/atomic
包里现在定义了新的类型: Bool
, Int32
, Int64
, Uint32
, Uint64
, Uintptr
, and Pointer
。
这些新的类型定义了相应的原子方法,要修改或者读取这些类型的变量的值就必须使用该类型的原子方法,这样可以避免误操作。
type Bool struct {
// contains filtered or unexported fields
}
func (x *Bool) CompareAndSwap(old, new bool) (swapped bool)
func (x *Bool) Load() bool
func (x *Bool) Store(val bool)
func (x *Bool) Swap(new bool) (old bool)
比如上面的sync/atomic
包里的Bool
类型就有4个原子方法,要读取或者修改atomic.Bool
类型的变量的值就要使用这4个方法。
sync/atomic
包有了Pointer
类型后,开发者不需要先把变量转成unsafe.Pointer
类型再去调用sync/atomic
包里的函数,直接使用Pointer
类型的原子方法即可。
Int64
和Uint64
类型在结构体(structs)和分配的内存里会自动按照64位自动对齐,即使在32位系统上也是按照64位对齐。
路径查找(PATH lookups)
Command
和 LookPath
不再允许在当前目录查找可执行程序,这个修改解决了一个常见的安全问题,但是也带来了破坏性更新。
比如以前有段代码是exec.Command("prog")
,表示要执行当前目录下名为prog
的可执行文件(在Windows系统上对应的是prog.exe
),那使用Go 1.19后就不会生效了。可以参考 os/exec
包的说明来修改代码以适配Command
和LookPath
的改动。
在Windows系统上,Command
和LookPath
现在会感知 NoDefaultCurrentDirectoryInExePath
环境变量。我们可以在Windows系统上设置该环境变量来禁止从当前目录.
查找可执行程序。
核心库的微小改动
Go标准库在Go 1.19版本有很多细微的改动和优化,主要涵盖以下内容:
Reader
现在会忽略掉ZIP文件开头的非ZIP数据部分,这在读一些Java的JAR文件时会很有必要。Read
不再缓存从操作系统里获取的随机数。对于Plan 9操作系统,Read
被重新实现了,用fast key erasure替换掉了ANSI X9.31算法。tls10default
GODEBUG
选项在Go 1.19版本已经被移除。 不过,我们还是可以通过设置Config.MinVersion
来支持client侧使用TLS 1.0协议。根据RFC 5246中7.4.1.4章节和RFC 8446中4.2章节的要求,TLS server和client现在会拒绝TLS握手里重复的扩展(duplicate extensions)。CreateCertificate
不再支持使用MD5WITHRSA
的签名算法来创建证书。CreateCertificate
不再接受SerialNumber为负数。ParseCertificate
和ParseCertificateRequest
现在会拒绝包含有重复扩展的证书和CSR(Certifcate Signing Request)。新方法
CertPool.Clone
和CertPool.Equal
可以克隆一个CertPool
,并且检查2个CertPool
是否相同。新函数
ParseRevocationList
提供了一个更快、更安全的方式去使用CRL解析器(parser)。CertificateList
和TBSCertificateList
现在被废弃了,应该使用新的crypto/x509
CRL functionality。新的
EM_LONGARCH
andR_LARCH_*
常量现在支持龙芯loong64架构。引入了新方法
File.COFFSymbolReadSectionDefAux
,该方法返回COFFSymbolAuxFormat5
类型,可以让开发者访问PE文件里的COMDAT信息。新接口
AppendByteOrder
提供了高效的方法用于把uint16
,uint32
,或uint64
添加到一个byte切片里。BigEndian
和LittleEndian
都实现了该接口。新方法
Reader.InputOffset
会返回当前读到的位置,以偏移的字节数来表示,类似于encoding/json
包里的Decoder.InputOffset
。新方法
Decoder.InputPos
会返回当前读到的位置,以行和列来表示,类似于encoding/csv
包里的Decoder.FieldPos
方法。新函数
TextVar
定义了一个encoding.TextUnmarshaler
参数,允许命令行里传入的flag变量使用big.Int
,netip.Addr
和time.Time
类型。go/parser
会把~x
解析为一元表达式(unary expression),其中操作符是~
,~
操作符的官方说明参考 token.TILDE。当类型约束(type constraint)用在错误的上下文时,比如
~int
,可以允许更好的错误恢复。新方法
Func.Origin
和Var.Origin
会返回Func
和Var
实例化后的对象。当目标图像和源头像都是
image.NRGBA
或者都是image.NRGBA64
类型时,operator为Src
的Draw
会保留non-premultiplied-alpha颜色。其实Go 1.17及更早版本的行为就是如此,但是Go 1.18版本做库优化的时候改变了这个行为,Go 1.19版本将这个行为还原了。
NopCloser
的结果现在实现了WriterTo
接口。MultiReader
的结果现在无条件地实现了WriterTo
。如果任何底层的reader没有实现WriteTo
,也会模拟WriteTo
的行为。.js
扩展名的文件本来应该被mime包识别为text/plain
类型,但是在Windows系统上有bug,会导致以.js
为扩展名的文件被mime包识别为text/javascript; charset=utf-8
类型。如果在Windows系统上,想让以
.js
为扩展名的文件被mime包识别为text/plain
,必须显示调用AddExtensionType
。ResponseWriter.WriteHeader
现在支持发送用户自定义的1xx信息头(informational header)。MaxBytesReader
的返回值io.ReadCloser
在超过读上限(read limit)后,会返回一个错误类型MaxBytesError
。HTTP client会把状态码为3xx但是没有
Location
header的Http Response返回给调用者,而不是直接当做错误处理。新增的
JoinPath
函数 和URL.JoinPath
方法可以把一组path元素组合在一起,创建一个新的URL
。URL
类型现在会区分没有host的URL和host为空的URL。举个例子,http:///path
是有host的,host为空,然后http:/path
就没有host。当URL的host为空时,
URL
类型里的字段OmitHost
的值会被设置为true
。如果
Cmd
类型的Dir
字段非空,Env
字段为nil,会隐式地为子进程设置PWD
环境变量,值为Dir
字段的值。新方法
Cmd.Environ
可以获取到运行cmd的环境,包括隐式设置的PWD
环境变量。Value.Bytes
方法现在除了接收slice切片,现在还接收可取址的数组(addressable array)。Value.Len
和Value.Cap
方法现在可以操作指向数组的指针,返回数组的长度。Go 1.18 release candidate 1, Go 1.17.8和 Go 1.16.15 这3个版本包含了对正则表达式解析可能带来的安全问题的修复,会拒绝嵌套很深的正则表达式。由于Go的补丁版本不能引入新的API,对于这种情况,解析器会返回
syntax.ErrInternalError
。Go 1.19对于上述情况,新增了一个更具体的错误
syntax.ErrNestingDepth
,不再返回syntax.ErrInternalError
。当Go可执行程序使用了
-trimpath
标记进行编译并且在进程运行环境里没有设置GOROOT
环境变量,GOROOT
函数会返回空串。新的
/sched/gomaxprocs:threads
度量指标 会报告runtime.GOMAXPROCS
的当前值。新的
/cgo/go-to-c-calls:calls
度量指标 会报告Go调用C的总次数。这个指标等同于runtime.NumCgoCall
函数的执行结果。新的
/gc/limiter/last-enabled:gc-cycle
度量指标 在GC CPU limiter开启时,会报告最新的GC循环(cycle)。可以参考runtime notes](https://tip.golang.org/doc/go...) 了解更多关于GC CPU limiter的细节。pprof
在收集goroutine profile时做了优化,可以大大减少对应用程序的性能影响。所有Unix操作系统上做
pprof
的heap profile结果都包含了MaxRSS
,之前只有GOOS=android
,darwin
,ios
和linux
系统上才会包含有MaxRSS
结果。race detector在Go 1.19版本做了升级,使用v3版本的 thread sanitizer,支持除了
windows/amd64
和openbsd/amd64
的所有平台,windows/amd64
和openbsd/amd64
平台仍然使用v2版本的thread sanitizer。和v2版本相比,v3版本速度提升了1.5-2倍,并且内存开销减半,还不限制goroutine的数量。
在Linux操作系统上,race detector现在要求glibc的版本最低是2.17。
race detector现在支持
GOARCH=s390x
架构。新版的thread sanitizer不再支持
openbsd/amd64
平台,因此openbsd/amd64
平台还是会沿用旧的v2版本的thread sanitizer。当tracing和 CPU profiler 同时开启时,tracing也会记录CPU Profile采样的结果。
Go自带的排序算法使用了pattern-defeating quicksort进行重写,速度更快。
新的函数 Find 类似 函数Search ,但是更好用。
Find
函数会额外返回一个bool值,用于表示是否找到了相同的数。Quote
函数和相关函数为了和其它ASCII码值保持一致,会引用字符U+007F为\x7f
,而不是\u007f
。对于PowerPC (
GOARCH=ppc64
,ppc64le
)架构,Syscall
,Syscall6
,RawSyscall
,和RawSyscall6
函数的第2个返回值r2
现在永远返回0,而不是之前的未定义值(undefined value)。对于AIX和Solaris系统,可以使用
Getrusage
函数了。新方法
Duration.Abs
可以得到duration的绝对值,更方便和安全,其中对于边界情况,−2⁶³ 会被转换为 2⁶³−1。新方法
Time.ZoneBounds
可以返回指定时间所在时区的开始和结束时间。
推荐阅读
想了解Go泛型的使用方法、设计思路和最佳实践,推荐大家阅读:
想了解Go原子操作和使用方法,推荐大家阅读:
开源地址
文章和示例代码开源在GitHub: Go语言初级、中级和高级教程。
公众号:coding进阶。关注公众号可以获取最新Go面试题和技术栈。
个人网站:Jincheng's Blog。
知乎:无忌。
福利
我为大家整理了一份后端开发学习资料礼包,包含编程语言入门到进阶知识(Go、C++、Python)、后端开发技术栈、面试题等。
关注公众号「coding进阶」,发送消息 backend 领取资料礼包,这份资料会不定期更新,加入我觉得有价值的资料。还可以发送消息「进群」,和同行一起交流学习,答疑解惑。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。