Go 1.14 新功能
1 Go 1.14简介
最新的Go版本1.14,是在Go 1.13半年后发布的。它的大部分变化是在工具链、运行时和库的实现上。一如既往地,该版本保持了Go 1的兼容性承诺。希望所有的 Go 程序都能像以前一样继续编译和运行。
go命令中的模块支持现在已经可以投入生产环境使用,我们鼓励所有用户迁移到Go模块进行依赖性管理。如果您由于Go工具链中的问题而无法迁移,请确保该问题有一个开放的问题备案。(如果问题不在Go1.15里程碑上,请告诉我们为什么它妨碍了您的迁移,以便我们能够适当地优先处理它。)
2 对语言的修改
根据重叠接口的提议,Go 1.14 现在允许嵌入具有重叠方法集的接口:来自嵌入接口的方法可以与(嵌入)接口中已经存在的方法具有相同的名称和相同的签名。这就解决了通常(但不限于)发生在菱形嵌入图中的问题。接口中明确声明的方法必须像以前一样保持唯一性。
3 移植
3.1 Darwin
Go 1.14是最后一个能在macOS 10.11 El Capitan上运行的版本。Go 1.15 需要 macOS 10.12 Sierra 或更高版本。
Go 1.14 是最后一个在 macOS 上支持 32 位二进制文件的 Go 版本(darwin/386 端口)。从macOS 10.15 (Catalina)开始,它们不再被macOS支持。Go继续支持64位的darwin/amd64端口。
Go 1.14 很可能是最后一个支持 iOS、iPadOS、watchOS 和 tvOS(darwin/arm 端口)的 32 位二进制文件的 Go 版本。Go继续支持64位的darwin/arm64端口。
3.2 Windows
Windows 上的 Go 二进制文件现在已经启用了 DEP (Data Execution Prevention) 功能。
在 Windows 上,通过 os.OpenFile 以 os.O_CREATE 标志创建文件,或者通过 syscall.Open 以 syscall.O_CREAT 标志创建文件,如果在权限参数中没有设置 0o200 位 (所有者写权限),则现在会将文件创建为只读。这使得Windows上的行为更像Unix系统上的行为。
3.3 WebAssembly
通过 js.Value 对象从 Go 引用的 JavaScript 值现在可以进行垃圾回收。
js.Value 值不能再使用 == 操作符进行比较,而必须使用 Equal 方法进行比较。
js.Value 现在拥有 IsUndefined、IsNull 和 IsNaN 方法。
3.4 RISC-V
Go 1.14 包含对 Linux 上 64 位 RISC-V 的实验性支持(GOOS=linux,GOARCH=riscv64)。请注意,性能、汇编语法的稳定性,以及正确性问题都在不断改进当中。
3.5 FreeBSD
Go 现在支持 64 位 ARM 架构的 FreeBSD 12.0 或更高版本 (freebsd/arm64 port)。
3.6 Native Client (NaCl)
正如Go 1.13版本说明中所宣布的,Go 1.14放弃了对Native Client平台的支持(GOOS=nacl)。
3.7 Illumos
现在,运行时尊重 runtime.NumCPU 的 zone CPU cap(zone.cpu-cap 资源控制)和 GOMAXPROCS 的默认值。
4 工具
4.1 Vendoring
当主模块包含一个顶级供应商目录,并且它的go.mod文件指定了go 1.14或更高版本时,go命令现在默认为-mod=vendor,用于接受该标志的操作。该标志的一个新值 -mod=mod 会使得go 命令从模块缓存中加载模块(就像没有供应商目录时一样)。
当-mod=vendor被设置时(显式或默认),go命令现在会验证主模块的vendor/modules.txt文件与go.mod文件是否一致。
go list -m 不再省略那些没有在供应商目录下提供包的过渡性依赖关系。现在,如果设置了 -mod=vendor,并且要求提供 vendor/modules.txt 中没有提到的模块的信息,那么它将明确地失败。
4.2 Flags
go get 命令不再接受 -mod 标志。以前,这个标志的设置要么被忽略,要么会导致编译失败,现在,当go.mod文件为只读且没有顶层供应商目录时,默认设置是mod=readonly。
-modcacherw 是一个新的标志,它指示 go 命令将模块缓存中新创建的目录保留在默认的权限,而不是让它们变成只读。使用这个标志会使测试或其他工具更有可能意外地添加未包含在模块验证校验中的文件。然而,它允许使用 rm -rf (而不是 go clean -modcache) 来删除模块缓存。
-modfile=file 是一个新的标志,它指示 go 命令读取(也可能写入)一个备用的 go.mod 文件,而不是模块根目录下的文件。一个名为 go.mod 的文件仍然必须存在,以便确定模块根目录,但它不会被访问。当指定了 -modfile 时,也会使用一个备用的 go.sum 文件:它的路径是由 -modfile 标志衍生出来的,它修剪了 .mod 扩展名,并附加了 .sum。
4.3 环境变量
GOINSECURE 是一个新的环境变量,它指示 go 命令在直接从其源头获取某些模块时,不需要 HTTPS 连接,并跳过证书验证。和现有的 GOPRIVATE 变量一样,GOINSECURE 的值是一个以逗号分隔的 glob 模式列表。
4.4 模块外的命令
当显式启用模块感知模式时(通过设置GO111MODULE=on),如果没有go.mod文件存在,大多数模块命令的功能会受到限制。例如,go build、go run和其他构建命令只能构建标准库中的包和命令行中指定为.go文件的包。
以前,go 命令会将每个包的路径解析为模块的最新版本,但不会记录模块的路径或版本。这导致了缓慢的、不可复制的构建。
go get和以前一样,go mod下载和go list -m也可以继续工作。
4.5 +不兼容的版本
如果一个模块的最新版本包含一个 go.mod 文件,go get 将不再升级到该模块的不兼容的主要版本,除非明确要求或已经需要这样的版本。当直接从版本控制中获取时,go list 也会省略这样一个模块的不兼容的主要版本,但如果有代理报告,则可能会包含它们。
4.6 go.mod文件维护
除 go mod tidy 以外的 go 命令不再删除指定间接依赖关系版本的 require 指令,该依赖关系已经被主模块的其他(转义)依赖关系所隐含。
除 go mod tidy 以外的 go 命令不再编辑 go.mod 文件,如果这些改动只是表面上的。
当设置了 -mod=readonly 时,go 命令将不再因为缺少 go 指令或错误的 // 间接注释而失败。
4.7 模块下载
go 命令现在支持模块模式下的 Subversion 仓库。
go命令现在包括来自模块代理和其他HTTP服务器的纯文本错误信息的片段。只有当错误信息是有效的UTF-8并且只由图形字符和空格组成时才会显示。
4.8 测试
go test -v 现在会随时进行t.Log流式输出,而不必等待所有测试结束。
5 运行时
这个版本提高了大多数使用defer的性能,与直接调用延迟函数相比,几乎是零开销。因此,defer 现在可以在性能关键型代码中使用,而无需担心开销。
Goroutine 现在可以异步地先发制人。在没有调用函数的情况下,循环不再使调度器陷入死锁,或显著地延迟垃圾收集。除了windows/arm、darwin/arm、js/wasm和plan9/*之外,所有平台都支持这个功能。
实现抢占的一个结果是,在Unix系统上,包括Linux和macOS系统,用Go 1.14构建的程序将比用早期版本构建的程序收到更多信号。这意味着使用syscall或golang.org/x/sys/unix等包的程序将看到更多缓慢的系统调用失败,并出现EINTR错误。这些程序将不得不以某种方式来处理这些错误,最可能的是循环再次尝试系统调用。关于这方面的更多信息请参见man 7 signal for Linux系统或其他系统的类似文档。
在GOMAXPROCS的高值下,页面分配器的效率更高,产生的锁争用也更少。这一点最明显的表现是,在并行和高速地进行大型分配时,延迟更低,吞吐量更高。
由time.After、time.Tick、net.Conn.SetDeadline和朋友们使用的内部定时器效率更高,锁争用更少,上下文切换更少。这是一个性能上的改进,应该不会引起任何用户可见的变化。
6 编译器
这个版本增加了 -d=checkptr 作为编译时的选项,用于增加工具来检查 Go 代码是否动态地遵循 unsafe.Pointer 安全规则。这个选项默认是通过-race或-msan标志启用的(Windows除外),也可以通过-gcflags=all=-d=checkptr=0禁用。
当把unsafe.Pointer转换为*T时,产生的指针必须对T进行适当的对齐。
如果指针运算的结果指向一个Go堆对象,则unsafe.Pointer类型的操作数之一必须指向同一个对象。
目前不建议在Windows上使用-d=checkptr,因为它会在标准库中引起错误的警报。
编译器现在可以使用-json标志发出机器可读的关键优化日志,包括内联、转义分析、边界检查消除和nil检查消除。
详细的转义分析诊断(-m=2)现在又可以工作了。在上一个版本中,新的转义分析实现中已经放弃了这一点。
macOS 二进制文件中的所有Go符号现在都以下划线开头,遵循平台惯例。
此版本包含了对编译器插入的模糊覆盖工具的实验性支持。更多细节请参见问题 14565。这个 API 可能会在未来的版本中改变。
界限检查消除现在使用来自分片创建的信息,并可以消除对类型小于int的索引的检查。
7 核心程序库
7.1 新的字节序列哈希包
Go 1.14 包含了一个新的包,hash/maphash,它提供了字节序列的哈希函数。这些哈希函数用于实现哈希表或其他需要将任意字符串或字节序列映射到无符号64位整数上的统一分布的数据结构。
哈希函数具有抗碰撞性,但在密码学上并不安全。
给定字节序列的哈希值在单个进程中是一致的,但在不同的进程中会有所不同。
7.2 程序库的小改动
与以往一样,库中有各种小的改动和更新,这些改动和更新都是考虑到 Go 1 的兼容性承诺。
7.2.1 crypto/tls
已取消对SSL 3.0版本(SSLv3)的支持。请注意,SSLv3是TLS之前的加密协议。
TLS 1.3不能再通过GODEBUG环境变量禁用。使用Config.MaxVersion字段来配置TLS版本。
当通过 Config.Certificates 字段提供多个证书链时,现在会自动选择第一个与对等体兼容的证书链。例如这允许提供一个ECDSA和一个RSA证书,并让软件包自动选择最好的一个。请注意,除非设置了Certificate.Leaf字段,否则这种选择的性能会很差。
新的CipherSuites和InsecureCipherSuites函数返回一个当前实现的密码套件列表。新的 CipherSuiteName 函数返回一个密码套件 ID 的名称。
新的 (*ClientHelloInfo).Supp SupportsCertificate 和 (*CertificateRequestInfo).Supp SupportsCertificate 方法揭示了对等体是否支持某个证书。
tls包不再支持传统的Next Protocol Negotiation (NPN)扩展,现在只支持ALPN。在以前的版本中,它同时支持这两种协议。没有API的变化,应用程序的功能应该和以前一样。大多数其他客户端和服务器已经删除了NPN支持,而支持标准化的ALPN。
当TLS 1.2握手支持时,现在使用RSA-PSS签名。这不会影响大多数应用程序,但不支持RSA-PSS签名的自定义Certificate.PrivateKey实现将需要使用新的Certificate.SupportedSignatureAlgorithms字段来禁用它们。
如果Config.GetConfigForClient被设置,Config.Certificate和Config.GetCertificate现在都可以为零。如果回调既不返回证书也不返回错误,现在会发送unrecognized_name。
新的CertificateRequestInfo.Version字段为客户端证书回调提供了TLS版本。
新的 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 和 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 常量使用了最终的名称。用于之前称为TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305和TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305的密码套件。
7.2.2 crypto/x509
证书.CreateCRL现在支持Ed25519签发人。
7.2.3 debug/dwarf
debug/dwarf包现在支持读取DWARF版本5。
新方法(*Data).AddSection支持从输入文件向DWARF数据中添加任意新的DWARF部分。
新方法(*Reader).ByteOrder返回当前编译单元的字节顺序。这可用于解释以本机顺序编码的属性,如位置描述。
新方法(*LineReader).Files从行阅读器返回文件名表。这可以用来解释DWARF属性的值,如AttrDeclFile。
7.2.4 encoding/asn1
Unmarshal现在支持ASN.1字符串类型BMPString,由新的TagBMPString常量表示。
7.2.5 encoding/json
Decoder类型支持一个新的方法InputOffset,该方法返回当前解码器位置的输入流字节偏移量。
Compact 不再转义 U+2028 和 U+2029 字符,这从来都不是一个记录的功能。关于正确的转义,请参见HTMLEscape。
Number不再接受无效的数字,以更接近文档中的行为。如果程序需要接受无效的数字,比如空字符串,可以考虑用Unmarshaler包装类型。
7.2.6 go/build
Context类型有一个新的字段Dir,可用于设置构建的工作目录。默认值是运行进程的当前目录。在模块模式下,它用于定位主模块。
7.2.7 go/doc
新函数NewFromFiles从一个*ast.File's列表中计算包文档,并将实例与适当的包元素关联起来。新的信息可以在包、类型和Func类型中的一个新的Examples字段中获得,并在Examples类型中的一个新的Suffix字段中获得。
7.2.8 io/ioutil
TempDir 现在可以创建名字有可预测前缀和后缀的目录。与 TempFile 一样,如果模式中包含 "*",随机字符串将取代最后的 "*"。
7.2.9 log
新的Lmsgprefix标志可以用来告诉日志函数在日志消息之前立即发出可选的输出前缀,而不是在行的开头。
7.2.10 math
新的FMA函数以浮点方式计算x*y+z,x*y计算没有中间舍入。一些架构使用专用的硬件指令来实现这种计算,以获得额外的性能。
7.2.11 math/big
GCD方法现在允许输入a和b为零或负。
7.2.12 math/bits
新函数 Rem、Rem32 和 Rem64 支持计算余数,即使商溢出时也是如此。
7.2.13 mime
.js和.mjs文件的默认类型现在是text/javascript而不是application/javascript。这与IETF草案中把application/javascript视为过时的规定是一致的。
7.2.14 mime/multipart
新的Reader方法NextRawPart支持获取下一个MIME部分,而不需要透明地解码引号内的可打印数据。
7.2.15 net/http
新的Header方法Values可以用来获取与canonicalized key相关联的所有值。
新的传输字段DialTLSContext可以用来指定一个可选的拨号函数,用于为非屏蔽的HTTPS请求创建TLS连接。这个新字段可以用来代替DialTLS,DialTLS现在被认为是过时的;DialTLS将继续工作,但新的代码应该使用DialTLSContext,它允许传输在不再需要时立即取消拨号。
在 Windows 上,ServeFile 现在可以正确地为大于 2GB 的文件提供服务。
7.2.16 net/http/httptest
启用HTTP2,支持在测试服务器上启用HTTP/2。
7.2.17 net/textproto
新的MIMEHeader方法Values可以用来获取与canonicalized key相关的所有值。
7.2.18 net/url
当解析一个URL失败时(例如通过Parse或ParseRequestURI),产生的错误信息现在将引用无法解析的URL。这提供了更清晰的结构和与其他解析错误的一致性。
7.2.19 os/signal
在Windows上,CTRL_CLOSE_EVENT、CTRL_LOGOFF_EVENT和CTRL_SHUTDOWN_EVENT事件现在会产生一个syscall.SIGTERM信号,类似于Control-C和Control-Break产生syscall.SIGINT信号的方式。
7.2.20 plugin
该插件包现在支持freebsd/amd64。
7.2.21 reflect
StructOf现在支持通过设置StructField元素中的PkgPath字段来创建带有未导出字段的结构类型。
7.2.22 runtime
runtime.Goexit 不能再被递归的 panic/recover 终止。
在 macOS 上,SIGPIPE 不再转发到 Go 运行时初始化之前安装的信号处理程序。这是必要的,因为macOS将SIGPIPE传递给主线程,而不是写到封闭管道的线程。
7.2.23 runtime/pprof
生成的配置文件不再包括用于内联标记的伪 PC。内联函数的符号信息以 pprof 工具所期望的格式进行编码。这是对最近版本中引入的回归的修正。
7.2.24 strconv
NumError类型现在有一个Unwrap方法,可以用来检索转换失败的原因。这支持使用带有error.Is的NumError值来查看底层错误是strconv.ErrRange还是strconv.ErrSyntax。
7.2.25 sync
现在,解锁一个高度争用的Mutex,可以直接将CPU交给下一个等待该Mutex的goroutine。这显著提高了高CPU数量机器上高竞争Mutex的性能。
7.2.26 Testing
测试包现在支持清理功能,在测试或基准完成后,分别调用T.Cleanup或B.Cleanup来调用。
7.2.27 text/template
Text/template 包现在可以正确地报告将括号参数用作函数时的错误。这最常见的是在错误的情况下出现,如{{if (eq .F "a") 或 (eq .F "b")}}。这应该写成{{if或(eq .F "a") (eq .F "b")}}。错误的情况从来没有像预期的那样工作,现在将以不能给非函数提供参数的错误来报告。
7.2.28 unicode
整个系统的unicode包和相关支持从Unicode 11.0升级到Unicode 12.0,增加了554个新字符,其中包括4个新脚本,61个新表情。
8 参考
- 点赞
- 收藏
- 关注作者
评论(0)