Go 1.19要来了,看看都有哪些变化-第4篇
前言
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版本有很多细微的改动和优化,主要涵盖以下内容:
- archive/zip
Reader
现在会忽略掉ZIP文件开头的非ZIP数据部分,这在读一些Java的JAR文件时会很有必要。
- crypto/rand
Read
不再缓存从操作系统里获取的随机数。对于Plan 9操作系统,Read
被重新实现了,用fast key erasure替换掉了ANSI X9.31算法。
- crypto/tls
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)。
- crypto/x509
CreateCertificate
不再支持使用MD5WITHRSA
的签名算法来创建证书。
CreateCertificate
不再接受SerialNumber为负数。
ParseCertificate
和ParseCertificateRequest
现在会拒绝包含有重复扩展的证书和CSR(Certifcate Signing Request)。
新方法CertPool.Clone
和CertPool.Equal
可以克隆一个CertPool
,并且检查2个CertPool
是否相同。
新函数ParseRevocationList
提供了一个更快、更安全的方式去使用CRL解析器(parser)。
- crypto/x509/pkix
CertificateList
和TBSCertificateList
现在被废弃了,应该使用新的crypto/x509
CRL functionality。
- debug
新的EM_LONGARCH
andR_LARCH_*
常量现在支持龙芯loong64架构。
- debug/pe
引入了新方法File.COFFSymbolReadSectionDefAux
,该方法返回COFFSymbolAuxFormat5
类型,可以让开发者访问PE文件里的COMDAT信息。
- encoding/binary
新接口AppendByteOrder
提供了高效的方法用于把uint16
,uint32
,或uint64
添加到一个byte切片里。
BigEndian
和LittleEndian
都实现了该接口。
- encoding/csv
新方法Reader.InputOffset
会返回当前读到的位置,以偏移的字节数来表示,类似于encoding/json
包里的Decoder.InputOffset
。
- encoding/xml
新方法Decoder.InputPos
会返回当前读到的位置,以行和列来表示,类似于encoding/csv
包里的Decoder.FieldPos
方法。
- flag
新函数TextVar
定义了一个encoding.TextUnmarshaler
参数,允许命令行里传入的flag变量使用big.Int
,netip.Addr
和time.Time
类型。
- fmt
新函数Append
,Appendf
和Appendln
可以添加格式化的数据到byte切片中。
- go/parser
go/parser
会把~x
解析为一元表达式(unary expression),其中操作符是~
,~
操作符的官方说明参考 token.TILDE。
当类型约束(type constraint)用在错误的上下文时,比如~int
,可以允许更好的错误恢复。
- go/types
新方法Func.Origin
和Var.Origin
会返回Func
和Var
实例化后的对象。
- hash/maphash
新函数Bytes
和String
提供了高效的方式用于对一个byte slice或者字符串做hash。
- html/template
FuncMap
类型现在是text/template
包里FuncMap
类型的别名,本身不再是一个独立的类型。
- image/draw
当目标图像和源头像都是image.NRGBA
或者都是image.NRGBA64
类型时,operator为Src
的Draw
会保留non-premultiplied-alpha颜色。
其实Go 1.17及更早版本的行为就是如此,但是Go 1.18版本做库优化的时候改变了这个行为,Go 1.19版本将这个行为还原了。
- io
NopCloser
的结果现在实现了WriterTo
接口。
MultiReader
的结果现在无条件地实现了WriterTo
。如果任何底层的reader没有实现WriteTo
,也会模拟WriteTo
的行为。
- mime
.js
扩展名的文件本来应该被mime包识别为text/plain
类型,但是在Windows系统上有bug,会导致以.js
为扩展名的文件被mime包识别为text/javascript; charset=utf-8
类型。
如果在Windows系统上,想让以.js
为扩展名的文件被mime包识别为text/plain
,必须显示调用AddExtensionType
。
- net/http
ResponseWriter.WriteHeader
现在支持发送用户自定义的1xx信息头(informational header)。
MaxBytesReader
的返回值io.ReadCloser
在超过读上限(read limit)后,会返回一个错误类型MaxBytesError
。
HTTP client会把状态码为3xx但是没有Location
header的Http Response返回给调用者,而不是直接当做错误处理。
- net/url
新增的JoinPath
函数 和URL.JoinPath
方法可以把一组path元素组合在一起,创建一个新的URL
。
URL
类型现在会区分没有host的URL和host为空的URL。举个例子,http:///path
是有host的,host为空,然后http:/path
就没有host。
当URL的host为空时,URL
类型里的字段OmitHost
的值会被设置为true
。
- os/exec
如果Cmd
类型的Dir
字段非空,Env
字段为nil,会隐式地为子进程设置PWD
环境变量,值为Dir
字段的值。
新方法Cmd.Environ
可以获取到运行cmd的环境,包括隐式设置的PWD
环境变量。
- reflect
Value.Bytes
方法现在除了接收slice切片,现在还接收可取址的数组(addressable array)。Value.Len
和Value.Cap
方法现在可以操作指向数组的指针,返回数组的长度。
- regexp/syntax
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
。
- runtime
GOROOT
函数会返回空串,当Go可执行程序使用了-trimpath
标记进行编译并且没有在进程运行环境里没有设置GOROOT
环境变量。
- runtime/metrics
新的/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的细节。
- runtime/pprof
pprof
在收集goroutine profile时做了优化,可以大大减少对应用程序的性能影响。
所有Unix操作系统上做pprof
的heap profile结果都包含了MaxRSS
,之前只有GOOS=android
,darwin
,ios
和linux
系统上才会包含有MaxRSS
结果。
- runtime/race
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。
- runtime/trace
当tracing和 CPU profiler 同时开启时,tracing也会记录CPU Profile采样的结果。
- sort
Go自带的排序算法使用了pattern-defeating quicksort进行重写,速度更快。
新的函数 Find 类似 函数Search ,但是更好用。Find
函数会额外返回一个bool值,用于表示是否找到了相同的数。
- strconv
Quote
函数和相关函数为了和其它ASCII码值保持一致,会引用字符U+007F为\x7f
,而不是\u007f
。
- syscall
对于PowerPC (GOARCH=ppc64
,ppc64le
)架构,Syscall
,Syscall6
,RawSyscall
,和RawSyscall6
函数的第2个返回值r2
现在永远返回0,而不是之前的未定义值(undefined value)。
对于AIX和Solaris系统,可以使用Getrusage
函数了。
- time
新方法Duration.Abs
可以得到duration的绝对值,更方便和安全,其中对于边界情况,?2?3 会被转换为 2?3?1。
新方法Time.ZoneBounds
可以返回指定时间所在时区的开始和结束时间。
- 官方教程:Go泛型入门
- 一文读懂Go泛型设计和使用场景
- 重磅:Go 1.18将移除用于泛型的constraints包
- 泛型最佳实践:Go泛型设计者教你如何用泛型
- Go并发编程之原子操作sync/atomic
公众号:coding进阶。关注公众号可以获取最新Go面试题和技术栈。
个人网站:Jincheng's Blog。
知乎:无忌。
福利 我为大家整理了一份后端开发学习资料礼包,包含编程语言入门到进阶知识(Go、C++、Python)、后端开发技术栈、面试题等。
【Go 1.19要来了,看看都有哪些变化-第4篇】关注公众号「coding进阶」,发送消息 backend 领取资料礼包,这份资料会不定期更新,加入我觉得有价值的资料。还可以发送消息「进群」,和同行一起交流学习,答疑解惑。
References
- https://tip.golang.org/doc/go...
推荐阅读
- 我若离去,后会无期
- 构建学习
- 书写是为了更好的思考
- 母亲老了,这些话请不要说!
- 我是不是想太多了
- 投稿|暑期档就此热起来了吗?
- 带着一份喜悦的心情回家
- 分布式锁用|分布式锁用 Redis 还是 Zookeeper(看完你就明白了!!)
- 后端|分布式锁用 Redis 还是 Zookeeper(看完你就明白了)
- C++开发|还不了解进程吗(就这一篇!)