上一篇:8千字详解Go1.20稳定版(一)+链接地址:https://developer.aliyun.com/article/1393845
编译器 Compiler
Go 1.20 添加了对配置文件引导优化 (PGO) 的预览支持。PGO 使工具链能够根据运行时配置文件信息执行特定于应用程序和工作负载的优化。目前,编译器支持 pprof CPU 配置文件,可以通过常规方式收集,例如runtime/pprof
或 net/http/pprof
包。要启用 PGO,请通过 -pgo
标志将 pprof 配置文件的路径传递给go
build
,如上所述。Go 1.20 使用 PGO 更积极地在热调用站点内联函数。一组具有代表性的 Go 程序的基准显示启用配置文件引导的内联优化可将性能提高约 3–4%。请参阅PGO 用户指南获取详细文档。我们计划在未来的版本中添加更多配置文件引导的优化。请注意,配置文件引导的优化是一个预览,因此请谨慎使用。
Go 1.20 编译器升级了它的前端以使用一种新的方式来处理编译器的内部数据,它修复了几个泛型类型问题并在泛型函数和方法中启用了类型声明。
编译器现在 默认拒绝带有编译器错误的匿名接口循环。这些源于嵌入式接口的巧妙使用, 并且一直存在细微的正确性问题,但我们没有证据表明它们确实在实践中使用过。假设没有用户报告受到此更改的不利影响,我们计划更新 Go 1.22 的语言规范以正式禁止它们,以便工具作者也可以停止支持它们。
Go 1.18 和 1.19 的构建速度有所下降,这主要是由于增加了对泛型的支持和后续工作。Go 1.20 将构建速度提高了 10%,使其与 Go 1.17 保持一致。相对于 Go 1.19,生成的代码性能也普遍略有提升。
链接器 Linker
glibc
在 Linux 上,链接器现在为链接时或musl
在链接时 选择动态解释器。
在 Windows 上,Go 链接器现在支持现代的基于 LLVM 的 C 工具链。
Go 1.20 对编译器生成的符号使用go:
andtype:
前缀,而不是go.
and type.
。这避免了名称以 . 开头的用户包的混淆go.
。该debug/gosym
软件包理解使用 Go 1.20 及更新版本构建的二进制文件的新命名约定。
引导程序 Bootstrap
当从源代码构建 Go 版本GOROOT_BOOTSTRAP
且未设置时,以前版本的 Go 在目录中查找 Go 1.4 或更高版本的引导工具链 $HOME/go1.4
(%HOMEDRIVE%%HOMEPATH%\go1.4
在 Windows 上)。 Go 1.18 和 Go 1.19在回退到 之前首先寻找$HOME/go1.17
或,以预期在引导 Go 1.20 时需要使用 Go 1.17。Go 1.20 确实需要 Go 1.17 版本来进行引导,但我们意识到我们应该采用引导工具链的最新点版本,因此它需要 Go 1.17.13。Go 1.20 寻找或 回退到之前$HOME/sdk/go1.17``$HOME/go1.4``$HOME/go1.17.13``$HOME/sdk/go1.17.13``$HOME/go1.4
(以支持硬编码路径 $HOME/go1.4 但在那里安装了更新的 Go 工具链的系统)。未来,我们计划大约每年将引导工具链向前移动一次,特别是我们预计 Go 1.22 将需要 Go 1.20 的最终版本来进行引导。
核心库
New crypto/ecdh package
Go 1.20 添加了一个新crypto/ecdh
包,以明确支持 NIST 曲线和 Curve25519 上的椭圆曲线 Diffie-Hellman 密钥交换。
程序应该为 ECDH 使用crypto/ecdh
而不是低级功能 crypto/elliptic
,而为更高级的用例使用第三方模块。
包装多个错误
Go 1.20 扩展了对错误包装的支持,允许一个错误包装多个其他错误。
一个错误e
可以通过提供一个Unwrap
返回[]error
.
和函数已更新以检查多重包装错误 errors.Is
。 errors.As
该fmt.Errorf
函数现在支持多次出现%w
格式动词,这将导致它返回一个包含所有这些错误操作数的错误。
新函数errors.Join
返回一个包含错误列表的错误。
HTTP 响应控制器
新 "net/http".ResponseController
类型提供对接口未处理的扩展的按请求功能的 "net/http".ResponseWriter
访问。
以前,我们通过定义ResponseWriter
可以实现的可选接口(例如 Flusher
. 这些接口不可发现且使用起来很笨拙。
该ResponseController
类型提供了一种更清晰、更易于发现的方式来添加每个处理程序的控件。Go 1.20 中还添加了两个这样的控件是 SetReadDeadline
和SetWriteDeadline
,它们允许设置每个请求的读写截止日期。例如:
func RequestHandler(w ResponseWriter, r *Request) { rc := http.NewResponseController(w) rc.SetWriteDeadline(time.Time{}) // 发送大响应时禁用 Server.WriteTimeout io.Copy(w, 大数据) }
新的 ReverseProxy 重写hook
httputil.ReverseProxy
转发代理包括一个新的 钩子Rewrite
函数,取代了以前的Director
钩子。
该Rewrite
挂钩接受一个 ProxyRequest
参数,该参数包括代理接收的入站请求和它将发送的出站请求。与Director
仅对出站请求进行操作的挂钩不同,这允许Rewrite
挂钩避免某些情况,在这些情况下,恶意入站请求可能导致挂钩添加的标头在转发之前被删除。请参阅问题 #50580。
该ProxyRequest.SetURL
方法将出站请求路由到提供的目的地并取代该NewSingleHostReverseProxy
功能。与 不同的NewSingleHostReverseProxy
是,SetURL
还设置了Host
出站请求的标头。
该 ProxyRequest.SetXForwarded
方法设置出站请求的X-Forwarded-For
、X-Forwarded-Host
和X-Forwarded-Proto
标头。使用 aRewrite
时,默认情况下不会添加这些标头。
Rewrite
使用这些功能的挂钩 示例是:
proxyHandler := &httputil.ReverseProxy{ 重写: func(r *httputil.ProxyRequest) { r.SetURL(outboundURL) // 转发请求到 outboundURL。 r.SetXForwarded() // 设置 X-Forwarded-* 标头。 r.Out.Header.Set("X-Additional-Header", "代理设置的header") }, }
ReverseProxy
User-Agent
当传入请求没有时, 不再向转发的请求添加标头。
library的小改动
与往常一样,库有各种小的变化和更新,考虑到 Go 1的兼容性承诺 。还有各种性能提升,这里就不一一列举了。
- archive/tar
设置GODEBUG=tarinsecurepath=0
环境变量后,Reader.Next
方法现在将返回ErrInsecurePath
文件名为绝对路径的条目的错误,指的是当前目录之外的位置,包含无效字符,或者(在 Windows 上)是保留名称,例如NUL
. Go 的未来版本可能会默认禁用不安全的路径。 - archive/zip
设置GODEBUG=zipinsecurepath=0
环境变量后,NewReader
现在将ErrInsecurePath
在打开包含绝对路径的任何文件名的存档时返回错误,指的是当前目录之外的位置,包含无效字符,或者(在 Windows 上)是保留名称,例如作为NUL
。Go 的未来版本可能会默认禁用不安全的路径。
从包含文件数据的目录文件中读取现在将返回错误。zip 规范不允许目录文件包含文件数据,因此此更改仅影响从无效存档中读取。 - bytes
新的CutPrefix
andCutSuffix
函数与 and 类似TrimPrefix
,TrimSuffix
但也报告字符串是否被修剪。
新Clone
函数分配字节切片的副本。 - context
新WithCancelCause
函数提供了一种方法来取消具有给定错误的上下文。可以通过调用新Cause
函数来检索该错误。 - crypto/ecdsa
使用支持的曲线时,所有操作现在都在恒定时间内实现。这导致 CPU 时间增加 5% 到 30%,主要影响 P-384 和 P-521。
新PrivateKey.ECDH
方法将 an 转换ecdsa.PrivateKey
为ecdh.PrivateKey
. - crypto/ed25519
该PrivateKey.Sign
方法和VerifyWithOptions
函数现在支持使用 Ed25519ph 对预散列消息进行签名,由Options.HashFunc
返回crypto.SHA512
. 他们现在还支持带有上下文的 Ed25519ctx 和 Ed25519ph,通过设置新Options.Context
字段来指示。 - crypto/RSA
新字段OAEPOptions.MGFHash
允许为 OAEP 解密单独配置 MGF1 哈希。
crypto/rsa 现在使用一个新的、更安全的、恒定时间的后端。这会导致解密操作的 CPU 运行时间增加大约 15%(amd64 上的 RSA-2048)和 45%(arm64 上的 RSA-4096),在 32 位架构上更多。加密操作比以前慢了大约 20 倍(但仍然比解密快 5-10 倍)。性能有望在未来的版本中得到改善。程序不得修改或手动生成 的字段PrecomputedValues
。 - crypto/subtle
新函数XORBytes
将两个字节片异或在一起。 - crypto/TLS
已解析的证书现在在所有主动使用该证书的客户端之间共享。在与共享其证书链的任何部分的服务器或服务器集合建立许多并发连接的程序中,内存节省可能非常重要。
对于由于证书验证失败而导致的握手失败,TLS 客户端和服务器现在返回一个新类型的错误CertificateVerificationError
,其中包括提供的证书。 - crypto/x509
ParsePKCS8PrivateKey
现在MarshalPKCS8PrivateKey
支持类型的键*crypto/ecdh.PrivateKey
。ParsePKIXPublicKey
现在MarshalPKIXPublicKey
支持类型的键*crypto/ecdh.PublicKey
。解析 NIST 曲线键仍然返回类型*ecdsa.PublicKey
和的值*ecdsa.PrivateKey
。使用他们的新ECDH
方法转换为crypto/ecdh
类型。
新SetFallbackRoots
功能允许程序定义一组备用根证书,以防操作系统验证程序或标准平台根包在运行时不可用。它最常与新包golang.org/x/crypto/x5…一起使用,它将提供最新的根包。 - debug/elf
尝试使用现在返回 的读取器或读取器读取SHT_NOBITS
部分 会 返回错误。Section.Data
Section.Open
定义了其他R_LARCH_*
常量以用于 LoongArch 系统。
定义了其他R_PPC64_*
常量以用于 PPC64 ELFv2 重定位。
的常量值R_PPC64_SECTOFF_LO_DS
已从 61 更正为 62。 - debug/gosym
由于Go 的符号命名约定发生了变化,处理 Go 二进制文件的工具应该使用 Go 1.20 的debug/gosym
包来透明地处理新旧二进制文件。 - debug/PE
定义了其他IMAGE_FILE_MACHINE_RISCV*
常量以用于 RISC-V 系统。 - 编码/二进制
ReadVarint
和ReadUvarint
函数现在将 在io.ErrUnexpectedEOF
读取部分值后返回,而不是io.EOF
. - encoding/xml
新Encoder.Close
方法可用于在完成编码时检查未闭合的元素。
解码器现在拒绝具有多个冒号的元素和属性名称,例如,以及解析为空字符串的命名空间,例如
xmlns:a=""
.
解码器现在拒绝在开始和结束标记中使用不同命名空间前缀的元素,即使这些前缀都表示相同的命名空间。 - 错误
新Join
函数返回一个包含错误列表的错误。 - 调速器
该Errorf
函数支持格式动词的多次出现%w
,返回一个错误,该错误解包到所有参数的列表%w
。
新FormatString
函数恢复对应于 a 的格式化指令State
,这在Formatter
. 实施。 - go/ast
新RangeStmt.Range
字段记录range
关键字在范围语句中的位置。
新增的File.FileStart
andFile.FileEnd
字段记录了整个源文件的开始和结束位置。 - go/token令牌
新FileSet.RemoveFile
方法从FileSet
. 长时间运行的程序可以使用它来释放与它们不再需要的文件关联的内存。 - go/types
新Satisfies
函数报告类型是否满足约束。 此更改与区分满足约束和实现接口 的新语言语义一致。 - IO
新OffsetWriter
包装底层WriterAt
并提供Seek
、Write
和WriteAt
方法,将其有效文件偏移位置调整固定量。 - 读写器
新错误 立即但成功SkipAll
终止。WalkDir
- math/big
math/big包 的广泛范围和依赖于输入的时序使其不适合实现密码学。标准库中的加密包不再 对攻击者控制的输入调用非平凡的Int方法。将来,确定 math/big 中的错误是否被视为安全漏洞将取决于它对标准库的更广泛影响。 - math/rand
math/rand包 现在自动为全局随机数生成器(由 和 等顶级函数使用Float64
)Int
生成一个随机值,并且顶级Seed
函数已被弃用。需要可重现的随机数序列的程序应该更喜欢分配自己的随机源,使用rand.New(rand.NewSource(seed))
.
需要较早一致的全局播种行为的程序可以GODEBUG=randautoseed=0
在其环境中设置。
顶层Read
函数已被弃用。几乎在所有情况下,crypto/rand.Read
都是更合适的。 - mime
该ParseMediaType
函数现在允许重复参数名称,只要名称的值相同即可。 - mime/multipart
该Reader
类型的方法现在包装了底层返回的错误io.Reader
。 - net
该函数现在在记录存在时LookupCNAME
始终如一地返回记录的内容。CNAME
以前在 Unix 系统上,当使用纯 Go 解析器时,如果记录引用的名称没有、 或记录,LookupCNAME
则会返回错误。此更改会修改 以匹配 Windows 上的先前行为,从而允许在存在时成功 。CNAME``A``AAAA``CNAME``LookupCNAME``LookupCNAME``CNAME
Interface.Flags
现在包括新标志FlagRunning
,表示一个可操作的活动接口。管理配置但不活动的接口(例如,因为未连接网络电缆)将FlagUp
设置但不FlagRunning
。
新Dialer.ControlContext
字段包含一个类似于现有Dialer.Control
挂钩的回调函数,它另外接受拨号上下文作为参数。 当不为零Control
时被忽略。ControlContext
Go DNS 解析器识别trust-ad
解析器选项。当在options trust-ad
中设置时resolv.conf
,Go 解析器将在 DNS 查询中设置 AD 位。解析器不在响应中使用 AD 位。
DNS 解析将检测更改/etc/nsswitch.conf
并在更改时重新加载文件。最多每五秒进行一次检查,与之前对/etc/hosts
和的处理相匹配/etc/resolv.conf
。 - 网络/http
该ResponseWriter.WriteHeader
功能现在支持发送1xx
状态代码。
新的Server.DisableGeneralOptionsHandler
配置设置允许禁用默认OPTIONS *
处理程序。
当从代理接收到请求的 HTTP 响应Transport.OnProxyConnectResponse
时,将调用 新挂钩。Transport``CONNECT
HTTP 服务器现在接受包含正文的 HEAD 请求,而不是将它们视为无效而拒绝。
函数返回的 HTTP/2 流错误net/http
可能会转换为golang.org/x/net/http2.StreamError
使用errors.As
.
前导和尾随空格从 cookie 名称中删除,而不是被拒绝为无效。例如,“name =value”的 cookie 设置现在被接受为设置 cookie“name”。 - net/netip
newIPv6LinkLocalAllRouters
andIPv6Loopback
函数net/netip
等同于net.IPv6loopback
andnet.IPv6linklocalallrouters
。 - pkg
在 Windows 上,该名称NUL
不再被视为 和 中的Mkdir
特例Stat
。
在 Windows 上,File.Stat
当文件是目录时,现在使用文件句柄检索属性。以前它会使用传递给的路径Open
,如果文件已被移动或替换,则该路径可能不再是文件句柄所代表的文件。此更改修改Open
为没有访问权限的打开目录FILE_SHARE_DELETE
,这与常规文件的行为相匹配。
在 Windows 上,File.Seek
现在支持查找到目录的开头。 - 操作系统/执行
新Cmd
字段Cancel
并WaitDelay
指定Cmd
当其关联Context
被取消或其进程退出时 I/O 管道仍由子进程保持打开状态时的行为。 - 路径/文件路径
新错误 立即但成功SkipAll
终止。Walk
新IsLocal
函数报告路径是否是目录的词法本地路径。例如,如果IsLocal(p)
istrue
,Open(p)
则将引用一个文件,该文件在词法上位于以当前目录为根的子树中。 - 反射 reflect
新的Value.Comparable
andValue.Equal
方法可用于比较两个Value
s 是否相等。Comparable
报告Equal
给定Value
接收器的操作是否有效。
新Value.Grow
方法扩展了一个切片以保证其他n
元素的空间。
新Value.SetZero
方法将一个值设置为其类型的零值。
Go 1.18 引入Value.SetIterKey
和Value.SetIterValue
方法。这些是优化:v.SetIterKey(it)
意味着等同于v.Set(it.Key())
. 这些实现错误地忽略了对未优化表单中存在的未导出字段的使用检查。Go 1.20 更正了这些方法以包括未导出的字段检查。 - 正则表达式
Go 1.19.2 和 Go 1.18.7 包含对正则表达式解析器的安全修复,使其拒绝会消耗过多内存的非常大的表达式。因为 Go 补丁版本没有引入新的 API,所以syntax.ErrInternalError
在这种情况下返回的解析器。Go 1.20 添加了一个更具体的错误,syntax.ErrLarge
解析器现在返回该错误。 - 运行时/cgo
Go 1.20 添加了新的Incomplete
标记类型。cgo 生成的代码将用于cgo.Incomplete
标记不完整的 C 类型。 - 运行时/指标
Go 1.20 添加了新的支持指标,包括当前GOMAXPROCS
设置 (/sched/gomaxprocs:threads
)、执行的 cgo 调用次数 (/cgo/go-to-c-calls:calls
)、互斥块总时间 (/sync/mutex/wait/total:seconds
) 以及垃圾收集中花费的各种时间度量。
基于时间的直方图指标现在不太精确,但占用的内存少得多。 - 运行时间/pprof
互斥配置文件样本现在已预先缩放,解决了如果采样率在执行期间发生变化,旧的互斥配置文件样本将被错误缩放的问题。
在 Windows 上收集的配置文件现在包含内存映射信息,可修复与位置无关的二进制文件的符号化问题。 - 运行时/跟踪
垃圾收集器的后台清扫器现在产生的频率降低了,从而导致执行跟踪中的无关事件大大减少。 - 字符串
新的CutPrefix
andCutSuffix
函数与 and 类似TrimPrefix
,TrimSuffix
但也报告字符串是否被修剪。 - 同步
新Map
方法Swap
、CompareAndSwap
和CompareAndDelete
允许以原子方式更新现有映射条目。 - 系统调用
在 FreeBSD 上,FreeBSD 11 及更早版本所需的兼容性垫片已被删除。
在 Linux 上,CLONE_*
定义了附加常量以用于该SysProcAttr.Cloneflags
字段。
在 Linux 上,newSysProcAttr.CgroupFD
和SysProcAttr.UseCgroupFD
字段提供了一种将子进程放入特定 cgroup 的方法。 - 测试
新方法B.Elapsed
报告基准的当前经过时间,这可能有助于计算使用 报告的速率ReportMetric
。 - 时间
新的时间布局常量DateTime
、DateOnly
和TimeOnly
为公共 Go 源代码调查中使用的三个最常见的布局字符串提供了名称。
新Time.Compare
方法比较两次。Parse
现在忽略其输入中的亚纳秒精度,而不是将这些数字报告为错误。
该Time.MarshalJSON
方法现在更加严格地遵守 RFC 3339。 - 统一码/utf16
新AppendRune
函数将给定符文的 UTF-16 编码附加到 uint16 切片,类似于utf8.AppendRune
.
微信号:wangzhongyang1993 公众号:程序员升职加薪之旅 B站视频:王中阳Go