Gopher们,Go 1.24.0 正式发布了!与 Go 1.23.0 相比,这个版本带来了众多改进。让我们一同看看 Go 1.24.0 都有哪些新变化吧!
在 Windows 下,请在 https://github.com/voidint/g/releases 下载适合您系统的版本。例如,如果您的系统是 64 位的,可以下载 g1.7.0.windows-amd64.zip 文件。
g install 1.24.0
g install 1.24.0
最新的 Go 版本 1.24 于 Go 1.23 发布六个月后正式推出。此版本的主要更改集中在工具链、运行时和库的实现上。与以往一样,此版本维持了 Go 1 的兼容性承诺。我们预计几乎所有的 Go 程序都能像以前一样编译和运行。
Go 1.24 现已全面支持泛型类型别名:类型别名可以像定义的类型一样被参数化。详细信息请参阅语言规范。目前,可以通过设置 GOEXPERIMENT=noaliastypeparams
来禁用此功能;但 aliastypeparams
设置将于 Go 1.25 被移除。
Go 模块现在可以使用 go.mod
中的工具指令来跟踪可执行依赖。这样就不再需要之前通过将工具作为空导入添加到名为“tools.go”的文件中的解决方法。go tool
命令现在可以运行这些工具,以及随 Go 发行版一起提供的工具。更多信息请参阅文档。
新的 -tool
标志用于 go get
,除了添加 require 指令外,还会将工具指令添加到当前模块的命名包中。
新的工具元模式引用当前模块中的所有工具。可以通过 go get tool
升级它们,或使用 go install tool
将它们安装到 GOBIN
目录中。
通过 go run
创建的可执行文件和 go tool
的新行为现在会被缓存到 Go 构建缓存中。这使得重复执行的速度更快,但会增加缓存的大小。详情见 #69290。
go build
和 go install
命令现在接受一个 -json
标志,该标志在标准输出中以结构化 JSON 格式报告构建输出和失败。有关报告格式的详细信息,请参阅 go help buildjson
。
此外,go test -json
现在在 JSON 测试结果中交织报告构建输出和失败。新动作类型可区分它们,但如果这在测试集成系统中导致问题,可以通过设置 GODEBUG
为 gotestjsonbuildtext=1
恢复为文本构建输出。
新的 GOAUTH
环境变量提供了一种灵活的方式来认证私有模块获取。更多信息请参阅 go help goauth
。
go build
命令现在根据版本控制系统标签和/或提交设置主模块的版本。如果有未提交的更改,将追加一个 +dirty 后缀。使用 -buildvcs=false
标志可省略版本控制信息。
新的 GODEBUG
设置 toolchaintrace=1
可用于跟踪 go
命令的工具链选择过程。
Cgo 支持新的注释来改善 C 函数的运行时性能。#cgo noescape cFunctionName
告诉编译器传递给 C 函数 cFunctionName
的内存不会逃逸。#cgo nocallback cFunctionName
告诉编译器 C 函数 cFunctionName
不会回调任何 Go 函数。更多信息请参阅 cgo 文档。
Cgo 目前拒绝编译对多个不兼容声明的 C 函数的调用。例如,如果 f
被声明为 void f(int)
和 void f(double)
,cgo 将报告错误,而不是可能生成一个不正确的调用序列。此版本新增了一个更好的检测机制,当不兼容声明出现在不同文件中时会出现这种错误条件。见 #67699。
objdump
工具现在支持在 64 位 LoongArch (GOARCH=loong64)、RISC-V (GOARCH=riscv64) 和 S390X (GOARCH=s390x) 上进行反汇编。
新的测试分析器报告测试、模糊测试、基准测试和示例的声明中的常见错误,例如格式错误的名称、错误的签名或文档中不存在的标识符的示例。其中一些错误可能导致测试不运行。此分析器是由 go test
返回的分析器子集之一。
现有的打印分析器现在会对形式为 fmt.Printf(s)
的调用报告诊断,其中 s
是一个非常量格式字符串,没有其他参数。这类调用几乎总是错误的,因为 s
的值可能包含 %
符号;建议使用 fmt.Print
代替。见 #60529。由于此检查在现有代码中产生的结果,因此仅在语言版本(由 go.mod
的 go 指令或 //go:build
注释指定)至少为 Go 1.24 时应用,以避免在升级到 1.24 Go 工具链时导致持续的集成失败。
现有的构建标签分析器现在会在 //go:build
指令中存在无效的 Go 主要版本构建约束时报告诊断。例如,//go:build go1.23.1
指向一个点发布;使用 //go:build go1.23
代替。见 #64127。
现有的 copylock
分析器现在报告诊断,当在三元组“for”循环中声明的变量如 for i := iter(); done(i); i = next(i) { ... }
包含 sync.Locker
,如 sync.Mutex
时。Go 1.22 更改了这些循环的行为,以创建每次迭代的新变量,从上一次迭代复制值;这个复制操作并不安全。见 #66387。
cmd/go
内部的二进制和测试缓存机制现在可以通过 GOCACHEPROG 环境变量实现 JSON 协议的子进程来实现,此功能之前处于 GOEXPERIMENT 下。有关协议细节,请参阅文档。
对运行时进行了一些性能优化,使 CPU 开销平均减少 2-3%。结果可能因应用而异。这些改进包括基于 Swiss Tables 的新的内置映射实现、对小对象的更高效内存分配,以及新的运行时内部互斥实现。
新的内置映射实现和新的运行时内部互斥体可以通过在构建时设置 GOEXPERIMENT=noswissmap
和 GOEXPERIMENT=nospinbitmutex
禁用。
编译器已不再允许定义接收器类型为 cgo 生成的新方法,但之前可以通过别名类型规避这一限制。Go 1.24 现在始终报告错误,如果接收器表示 cgo 生成的类型,无论是直接还是间接(通过别名类型)。
在 ELF 平台上,链接器现在默认生成 GNU 构建 ID(ELF NT_GNU_BUILD_ID 注释),以及在 macOS 上生成 UUID(Mach-O LC_UUID 负载命令)。构建 ID 或 UUID 来源于 Go 构建 ID。可以通过 -B none
链接器标志禁用该功能,或通过 -B 0xNNNN
链接器标志覆盖为用户指定的十六进制值。
如 Go 1.22 发布说明中所提到的,Go 1.24 现在要求 Go 1.22.6 或更高版本进行启动。我们预计 Go 1.26 将要求 Go 1.24 或更高版本的点发布进行启动。
新的 os.Root
类型提供了在特定目录内执行文件系统操作的能力。os.OpenRoot
函数打开一个目录并返回一个 os.Root
。os.Root
上的方法都在该目录内操作,并且不允许引用目录外的位置,包括通过符号链接指向目录外的位置。os.Root
上的方法与 os
包中可用的大多数文件系统操作相对应,例如 os.Root.Open
、os.Root.Create
、os.Root.Mkdir
和 os.Root.Stat
。
基准测试现在可以使用更快速且出错率更低的 testing.B.Loop
方法来执行基准迭代,例如 for b.Loop() { ... }
,来替代涉及 b.N
的典型循环结构,例如 for range b.N
。这种方法有两个显著的优势:
-count
下仅执行一次,这样开销大的初始化和清理步骤也只执行一次。新的 runtime.AddCleanup
函数是一种更灵活、更高效、出错率更低的最终化机制,相较于 runtime.SetFinalizer
。AddCleanup
可以将清理函数附加到一个对象上,并在对象不再可达时运行。与 SetFinalizer
不同,多个清理函数可以附加到同一个对象上,清理可以附加到内部指针上,且清理通常不会在对象形成循环时导致泄露,也不会延迟释放对象或其指向的对象。新代码应优先使用 AddCleanup
而非 SetFinalizer
。
新的 weak
包提供弱指针。弱指针是一种低级原语,用于创建内存高效的结构,如关联值的弱映射、用于包唯一性未覆盖内容的规范化映射和各种类型的缓存。为支持这些用例,本次发布还提供了 runtime.AddCleanup
和 maphash.Comparable
。
crypto/mlkem
包新的 crypto/mlkem
包实现了 ML-KEM-768 和 ML-KEM-1024。ML-KEM 是一种后量子密钥交换机制,以前称为 Kyber,并在 FIPS 203 中指定。
crypto/hkdf
、crypto/pbkdf2
和 crypto/sha3
包新的 crypto/hkdf
包实现了基于 HMAC 的提取和扩展密钥导出函数 HKDF,如 RFC 5869 所定义。
新的 crypto/pbkdf2
包实现了基于密码的密钥导出函数 PBKDF2,如 RFC 8018 所定义。
新的 crypto/sha3
包实现了 SHA-3 哈希函数及 SHAKE 和 cSHAKE 可扩展输出函数,符合 FIPS 202 的定义。
这三个包都是基于现有的 golang.org/x/crypto/...
包。
此次发布包含了一组机制,以促进 FIPS 140-3 的合规性。Go 加密模块是一组内部标准库包,透明地用于实现 FIPS 140-3 批准的算法。应用程序无需更改即可使用 Go 加密模块来调用批准的算法。
新的 GOFIPS140
环境变量可用于选择构建中使用的 Go 加密模块版本。新的 fips140 GODEBUG
设置可以在运行时启用 FIPS 140-3 模式。Go 1.24 包含 Go 加密模块版本 v1.0.0,该版本目前正在与 CMVP 认证实验室测试中。
testing/synctest
包新的实验性 testing/synctest
包提供对并发代码的测试支持。synctest.Run
函数在一个隔离的“泡泡”中启动一组 goroutines。在泡泡内,时间包函数在一个虚拟时钟上运行。synctest.Wait
函数等待当前泡泡中的所有 goroutines 阻塞。有关更多详细信息,请参阅包文档。
synctest
包是实验性的,必须在构建时通过设置 GOEXPERIMENT=synctest
来启用。该包的 API 在未来版本中可能会发生变化。有关更多信息和反馈,请参见问题 #67434。
archive/zip
和 archive/tar
中的 (*Writer).AddFS
实现现在为空目录写入目录头。
bytes
包添加了多个使用迭代器的函数:
Lines
返回一个迭代器,迭代经过换行符终止的字节切片中的行。SplitSeq
返回一个迭代器,迭代表所有在分隔符周围拆分的字节切片。SplitAfterSeq
返回一个迭代器,迭代在每个分隔符后拆分的字节切片。FieldsSeq
返回一个迭代器,迭代在空白字符序列周围拆分的字节切片,按 Unicode 字符串定义。FieldsFuncSeq
返回一个迭代器,迭代在满足条件的 Unicode 代码点序列周围拆分的字节切片。返回的值不再实现 NewCTR
、NewGCM
、NewCBCEncrypter
和 NewCBCDecrypter
方法。这些方法没有文档说明,并且在所有架构上不可用。相反,Block 值应直接传递给相关的 crypto/cipher
函数。目前,crypto/cipher
仍然会检查这些方法在 Block 值上的存在,即使它们不再被标准库使用。
新的 NewGCMWithRandomNonce
函数返回一个 AEAD,使用随机 nonce 在 Seal 期间生成并将其预先添加到密文中。
用于 crypto/aes
的 NewCTR
返回的 Stream 实现现在在 amd64 和 arm64 上速度是以前的数倍。
NewOFB
、NewCFBEncrypter
和 NewCFBDecrypter
现在被标记为弃用。OFB 和 CFB 模式没有认证,通常会导致主动攻击以操纵和恢复明文。建议应用程序改用 AEAD 模式。如果需要非认证的流模式,请使用 NewCTR
。
PrivateKey.Sign
现在如果随机源为 nil,则根据 RFC 6979 生成确定性签名。
md5.New
返回的值现在也实现了 encoding.BinaryAppender
接口。
Read
函数现在保证不会失败。它将始终返回 nil 作为错误结果。如果 Read
在从 Reader 读取时遇到错误,程序将不可恢复地崩溃。请注意,默认 Reader 使用的平台 API 被文档说明为始终成功,因此此更改仅会影响覆盖了 Reader 变量的程序。一个例外是版本低于 3.17 的 Linux 内核,其中默认 Reader 仍然打开 /dev/urandom
并可能失败。在 Linux 6.11 及更高版本中,Reader 现在使用通过 vDSO 的 getrandom
系统调用。这在小读取时速度更快数倍。在 OpenBSD 中,Reader 现在使用 arc4random_buf(3)
。
新的 Text
函数可用于生成密码安全的随机文本字符串。
GenerateKey
现在如果请求的密钥少于 1024 位将返回错误。所有 Sign
、Verify
、Encrypt
和 Decrypt
方法现在如果使用小于 1024 位的密钥也会返回错误。这样的密钥不安全,不应使用。可以通过设置 GODEBUG
为 rsa1024min=0
恢复旧行为,但我们建议仅在必要时和仅限于测试中使用,例如在测试文件中添加 //go:debug rsa1024min=0
行。新的 GenerateKey
示例提供了一个易于使用的标准 2048 位测试密钥。PrivateKey.Validate
之前,现在安全且更高效地调用 PrivateKey.Precompute
。在从 JSON 解码密钥时,Precompute
在部分填充的 PrecomputedValues
存在时变得更快。Validate
,并且 GenerateKey
可能会对破损的随机源返回新错误。即使某些值缺失,PrivateKey
的 Primes
和 Precomputed
字段现在也会被使用和验证。有关 RSA 密钥解析和序列化的更多更改,见下面的 crypto/x509
。SignPKCS1v15
和 VerifyPKCS1v15
现在支持 SHA-512/224、SHA-512/256 和 SHA-3。GenerateKey
现在采用稍微不同的方法生成私钥指数(使用卡迈克尔的φ而不是欧拉的φ)。极少数情况下,外部重新生成仅基于素因子的密钥可能会产生不同但兼容的结果。sha1.New
返回的值现在还实现了 encoding.BinaryAppender
接口。sha256.New
和 sha256.New224
返回的值现在也实现了 encoding.BinaryAppender
接口。sha512.New
、sha512.New384
、sha512.New512_224
和 sha512.New512_256
返回的值现在也实现了 encoding.BinaryAppender
接口。WithDataIndependentTiming
函数允许用户运行带有特定架构特征的函数,以确保特定指令不会受到数据值的时间干扰。这可以用来确保设计为在恒定时间运行的代码不会被 CPU 级特性优化,从而导致在可变时间内运行。目前,WithDataIndependentTiming
在 arm64 上使用 PSTATE.DIT
位,在其他架构上无效。将 GODEBUG
设置为 dataindependenttiming=1
可以为整个 Go 程序启用 DIT 模式。XORBytes
的输出必须与输入完全重叠或完全不重叠。之前的行为是未定义的,而现在 XORBytes
会引发恐慌。Config.EncryptedClientHelloKeys
字段来启用此功能。Config.CurvePreferences
为 nil 时默认启用。将 GODEBUG
设置为 tlsmlkem=0
可以恢复默认设置。这在处理无法正确处理大记录的有缺陷的 TLS 服务器时可能会有用,导致在握手期间出现超时(请参见 TLS 后量子 TL;DR 故障)。crypto/tls
包处理。Config.CurvePreferences
的顺序现在被忽略,内容仅在填充时用于确定启用哪些密钥交换。ClientHelloInfo.Extensions
字段列出了在 Client Hello 消息中收到的扩展 ID。这对指纹识别 TLS 客户端非常有用。x509sha1
的 GODEBUG
设置。Certificate.Verify
不再支持基于 SHA-1 的签名。encoding.BinaryAppender
和 encoding.TextAppender
接口。Certificate.PolicyIdentifiers
更改为 Certificate.Policies
。在解析证书时,这两个字段都会被填充,但在创建证书时,政策将从 Certificate.Policies
字段而不是 Certificate.PolicyIdentifiers
字段中获取。此更改可以通过将 GODEBUG
设置为 x509usepolicies=0
来恢复。Certificate.SerialNumber
字段的模板时,CreateCertificate
将使用符合 RFC 5280 的方法生成序列号,而不是失败。Certificate.Verify
现在支持政策验证,按照 RFC 5280 和 RFC 9618 的定义。新的 VerifyOptions.CertificatePolicies
字段可以设置为可接受的政策 OID 集。只有具有有效政策图的证书链将从 Certificate.Verify
返回。MarshalPKCS8PrivateKey
现在返回错误,而不是序列化无效的 RSA 密钥。(MarshalPKCS1PrivateKey
没有错误返回,对于无效密钥的行为仍然未定义。)ParsePKCS1PrivateKey
和 ParsePKCS8PrivateKey
现在会使用并验证编码的 CRT 值,因此可能会拒绝之前接受的无效 RSA 密钥。可以使用将 GODEBUG
设置为 x509rsacrt=0
来恢复到重新计算 CRT 值。debug/elf
包添加了对处理动态 ELF(可执行和可链接格式)文件中的符号版本的支持。新的 File.DynamicVersions
方法返回 ELF 文件中定义的动态版本列表。新的 File.DynamicVersionNeeds
方法返回此 ELF 文件要求的由其他 ELF 对象定义的动态版本列表。最后,新的 Symbol.HasVersion
和 Symbol.VersionIndex
字段指示符号的版本。引入了两个新的接口:TextAppender 和 BinaryAppender,用于将对象的文本或二进制表示追加到字节切片中。这些接口提供与 TextMarshaler 和 BinaryMarshaler 相同的功能,但不再每次都分配一个新切片,而是直接将数据追加到现有切片中。这些接口已由标准库中已经实现了 TextMarshaler 和/或 BinaryMarshaler 的类型所实现。
在序列化时,结构体字段的标签中新增了 omitzero 选项,如果其值为零则会被忽略。如果字段类型具有 IsZero() bool 方法,将用于判断该值是否为零。否则,只有当它的值是其类型的零值时,才会被视为零。omitzero 字段标签在想要省略零值时,比 omitempty 更加清晰且不容易出错。特别是,与 omitempty 不同的是,omitzero 会省略零值的 time.Time 值,这是一个常见的问题源头。
如果同时指定了 omitempty 和 omitzero,则当值为空或零(或两者皆是)时,该字段会被忽略。
UnmarshalTypeError.Field 现在包含嵌入结构,以提供更详细的错误信息。
所有通过一对方法(例如 Len() int 和 At(int) T)暴露序列的 go/types 数据结构现在也有返回迭代器的方法,从而简化如下代码:
params := fn.Type.(*types.Signature).Params()
for i := 0; i < params.Len(); i++ {
use(params.At(i))
}
可以简化为:
for param := range fn.Signature().Params().Variables() {
use(param)
}
这些方法包括:Interface.EmbeddedTypes、Interface.ExplicitMethods、Interface.Methods、MethodSet.Methods、Named.Methods、Scope.Children、Struct.Fields、Tuple.Variables、TypeList.Types、TypeParamList.TypeParams 和 Union.Terms。
现在返回的新值也实现了 encoding.BinaryAppender 接口。
返回的新值和 NewIEEE 现在也实现了 encoding.BinaryAppender 接口。
返回的新值现在也实现了 encoding.BinaryAppender 接口。
返回的 New32、New32a、New64、New64a、New128 和 New128a 现在也实现了 encoding.BinaryAppender 接口。
新增加的 Comparable 和 WriteComparable 函数可以计算任何可比较值的哈希值。这使得可以对任何可以用作 Go 映射键的内容进行哈希处理。
新增加的 DiscardHandler 是一个永远不启用且始终丢弃输出的处理器。
Level 和 LevelVar 现在实现了 encoding.TextAppender 接口。
Float、Int 和 Rat 现在实现了 encoding.TextAppender 接口。
对已弃用的顶级 Seed 函数的调用不再产生任何效果。要恢复旧行为,请使用 GODEBUG 设置 randseednop=0。有关更多背景信息,请参见提案 #67273。
ChaCha8 和 PCG 现在实现了 encoding.BinaryAppender 接口。
ListenConfig
现在默认使用 MPTCP。encoding.TextAppender
接口。Transport
对于收到请求的 1xx 信息响应的限制已更改。之前在接收到超过 5 个 1xx 响应后会终止请求并返回错误,而现在如果所有 1xx 响应的总大小超过配置的 Transport.MaxResponseHeaderBytes
设置,则才会返回错误。net/http/httptrace.ClientTrace.Got1xxResponse
跟踪钩子时,1xx 响应的总数没有限制。Got1xxResponse
钩子可以返回错误以终止请求。Transport
和 Server
现在具有一个 HTTP2 字段,允许配置 HTTP/2 协议设置。Server.Protocols
和 Transport.Protocols
字段提供了一种简单的方式来配置服务器或客户端使用的 HTTP 协议。Server.Protocols
包含 UnencryptedHTTP2
时,服务器将接受未加密端口上的 HTTP/2 连接。服务器可以在同一端口上同时接受 HTTP/1 和未加密的 HTTP/2。Transport.Protocols
包含 UnencryptedHTTP2
且不包含 HTTP1 时,传输将对 http://
URL 使用未加密的 HTTP/2。如果传输配置为同时使用 HTTP/1 和未加密的 HTTP/2,则将使用 HTTP/1。Addr
、AddrPort
和 Prefix
现在实现了 encoding.BinaryAppender
和 encoding.TextAppender
接口。URL
现在还实现了 encoding.BinaryAppender
接口。Current
现在可以在 Windows Nano Server 上使用。实现已更新以避免使用不在 Nano Server 中可用的 NetApi32 库的函数。Current
、Lookup
和 LookupId
现在支持以下内置服务用户帐户:Current
的性能显著提高。新的实现性能现在达到毫秒级,而以前的实现可能需要几秒钟甚至几分钟才能完成。Current
现在返回进程拥有的用户,而不是之前返回的错误。Regexp
现在实现了 encoding.TextAppender
接口。GOROOT
函数现已被弃用。新的代码中建议使用系统路径来查找“go”二进制文件,并使用 go env GOROOT
来查找其 GOROOT。strings
包新增了几个与迭代器配合使用的函数:Lines
返回一个迭代器,迭代一个字符串中的以换行符结束的行。SplitSeq
返回一个迭代器,迭代一个字符串中围绕分隔符拆分的所有子字符串。SplitAfterSeq
返回一个迭代器,迭代一个字符串中在每个分隔符后拆分的子字符串。FieldsSeq
返回一个迭代器,迭代一个字符串中围绕空白字符数组(由 unicode.IsSpace
定义)拆分的子字符串。FieldsFuncSeq
返回一个迭代器,迭代一个字符串中在满足谓词的 Unicode 代码点数组周围拆分的子字符串。sync.Map
的实现已更改,提升了性能,特别是在修改映射时。例如,对于不相交的键集的修改在较大的映射上不太可能产生竞争,并且不再需要任何 ramp-up 时间来实现低竞争的映射负载。GOEXPERIMENT=nosynchashtriemap
以切换回旧实现,并请提交问题。T.Context
和 B.Context
方法返回一个在测试完成后并在测试清理函数运行之前被取消的上下文。T.Chdir
和 B.Chdir
方法可用于在测试或基准测试期间更改工作目录。range-over-func
和 range-over-int
。Time
现在实现了 encoding.BinaryAppender
和 encoding.TextAppender
接口。正如在 Go 1.23 发布说明中宣布的,Go 1.24 要求使用 3.2 或更高版本的 Linux 内核。
Go 1.24 是最后一个支持 macOS 11 Big Sur 的版本。Go 1.25 将要求使用 macOS 12 Monterey 或更高版本。
新增了 go:wasmexport 编译指令,允许 Go 程序将函数导出到 WebAssembly 主机。
在 WebAssembly 系统接口预览 1(GOOS=wasip1 GOARCH=wasm)中,Go 1.24 支持通过指定 -buildmode=c-shared
构建 Go 程序作为反应器/库。
对于 go:wasmimport 函数,现在允许更多类型作为参数或返回值类型。具体来说,bool、string、uintptr 以及某些类型的指针被允许(详细信息请参见文档),此外,32 位和 64 位整数、浮点类型以及 unsafe.Pointer 也已被允许。这些类型同样被允许作为 go:wasmexport 函数的参数或返回值类型。
WebAssembly 的支持文件已从 misc/wasm 移动到 lib/wasm。
初始内存大小显著减小,特别是对于小型 WebAssembly 应用程序。
32 位的 windows/arm 端口 (GOOS=windows GOARCH=arm) 被标记为损坏。有关详细信息,请参见问题 #70705。