Go 1.24 版本于 2025 年 2 月发布,带来了多项改进和新功能,主要集中在工具链、运行时和标准库的实现上。此版本保持了 Go 1 的兼容性承诺,确保绝大多数 Go 程序能够继续编译和运行。
语言特性更新
泛型类型别名 (Generic Type Aliases)
在 Go 1.24 之前,类型别名(type alias)不能带有自己的类型参数(type parameters)。而从 Go 1.24 开始,这成为了可能。
什么是类型别名?
Go 允许使用 type A = B
创建类型别名,本质上只是另一个名字,两者完全等价。例如:
type MyInt = int
这里 MyInt
和 int
没有区别,编译器会直接将 MyInt
视为 int
。
泛型与 Go 1.24 之前的限制
Go 1.18 引入泛型后,可以定义带类型参数的类型,例如:
type Vector[T any] []T
这样,Vector[int]
就等同于 []int
,Vector[string]
就等同于 []string
。但在 Go 1.24 之前,你不能为泛型类型创建别名,例如:
// Go 1.24 之前,这是非法的
type VectorAlias[T any] = Vector[T] // ❌ 不允许
Go 1.24 的改进
从 Go 1.24 开始,你可以为泛型类型创建类型别名:
type Vector[T any] []T
type VectorAlias[T any] = Vector[T] // ✅ 现在可以了
这样,VectorAlias[int]
和 Vector[int]
完全等价。换句话说,类型别名现在也支持泛型,使代码更简洁、更易复用。
举个例子,假设我们需要一个 int
类型的 Vector
切片,可以这样定义:
type IntVector = Vector[int]
var v IntVector = []int{1, 2, 3}
fmt.Println(v) // 输出: [1 2 3]
这让类型定义更加灵活,避免了重复书写 Vector[int]
,提高了代码可读性。
相关阅读:Go 语言泛型用法详解
工具链更新
Tool 指令
在 Go 1.24 之前,开发者通常使用“空白导入”的方式来声明项目所依赖的开发工具,例如代码生成器、静态分析工具等。这种做法的主要目的是让 go mod
识别这些工具依赖,并将它们添加到 go.mod
文件中,方便进行依赖管理。
具体来说,开发者会在 tools.go
文件中使用 _
作为占位符来导入工具包,例如:
import _ "golang.org/x/tools/cmd/stringer"
即便代码中未直接使用该工具,go mod tidy
依然会将其记录在 go.mod
中。这种方式虽然有效,但略显 hack,主要是为了借助 go mod
统一管理依赖,包括工具的安装、更新和删除。
然而,从 Go 1.24 开始,官方引入了 tool
指令,为管理这些非运行时工具提供了一种更清晰、规范的方式。相比传统的空白导入,新方法更加直观,减少了不必要的包导入,使依赖管理更加简洁。
tool
指令的使用方式
- 声明工具依赖
使用
go get -tool
命令来显式添加工具。例如,要添加stringer
工具,可以执行:这样,go get -tool golang.org/x/tools/cmd/stringer
go.mod
文件会直接记录工具依赖,无需再通过import _
方式隐式引入。 - 运行工具
以前,运行这些工具时需要手动输入完整路径,而现在
go tool
命令简化了这一过程。例如:只需指定工具名即可,无需关心工具的安装路径,使得开发流程更加流畅。go tool stringer -type=MyType my_type.go
此外,Go 1.24 允许使用 go tool
元模式对所有工具执行操作,例如:
go get tool
可一次性升级所有工具。go install tool
可将所有工具安装到$GOBIN
目录中。
相关阅读:Golang tools: stringer 用法详解
构建缓存优化
在 Go 1.24 之前,构建缓存主要用于存储编译阶段的中间产物(即 build actions),但不会缓存最终生成的可执行文件(link actions)。这意味着,每次运行 go run
或 go tool
命令时,Go 都需要重新执行链接过程,导致执行效率受到影响。
从 Go 1.24 开始,go run
生成的可执行文件以及go tool
运行的工具都会被缓存。这一优化带来了以下好处:
- 提升执行速度:对于相同的程序或工具,后续运行时可以直接复用缓存,避免重复编译和链接,从而加快执行速度。
- 提高开发效率:在频繁运行
go run
或go tool
的开发场景下,减少了不必要的重复计算,使开发流程更加流畅。
同样,go tool
运行的工具现在也会被缓存,使后续执行更快,减少不必要的编译和加载时间。这对于经常使用 Go 工具链的开发者来说,是一个实用的改进。
不过,需要注意的是,这也意味着构建缓存的占用空间可能会增加。
JSON 输出
Go 1.24 版本在 JSON 输出方面有以下更新:
go build
和go install
命令:这两个命令现在接受-json
标志,该标志会将构建输出和失败信息以结构化的 JSON 格式报告到标准输出。关于报告格式的详细信息,可以参考go help buildjson
。go test -json
命令:该命令现在以 JSON 格式报告构建输出和失败信息,并与测试结果 JSON 交错在一起。这些信息通过新的Action
类型来区分。如果这在测试集成系统中引起问题,可以通过设置GODEBUG
为gotestjsonbuildtext=1
来恢复到文本构建输出。
go build
、go install
和 go test
命令的 JSON 输出功能,使其能够以结构化的 JSON 格式报告构建过程中的输出和错误信息。这对于自动化构建和测试流程,以及与各种集成系统的兼容性非常有帮助。
GOAUTH 环境变量
新的 GOAUTH
环境变量提供了一种灵活的身份验证私有模块获取方式。以下是 GOAUTH
的主要功能和使用方法:
认证指令列表:GOAUTH
环境变量包含一个由分号分隔的认证指令列表,用于与 go-import
和 HTTPS 模块镜像交互。
默认值为 netrc
:默认情况下,GOAUTH
会使用 NETRC
或用户主目录下的 .netrc
文件中的凭据。你也可以通过设置 NETRC
环境变量来指定 .netrc
文件的位置。
支持的认证命令:
off
:禁用认证。netrc
:使用NETRC
或~/.netrc
文件中的凭据。git dir
:在指定目录下运行git credential fill
,并使用其凭据。command
:执行给定命令并将生成的 header 附加到 HTTPS 请求。
命令输出格式:命令输出必须符合特定格式,以便 go
命令能够解析并使用凭据:
Response = { CredentialSet } .
CredentialSet = URLLine { URLLine } BlankLine { HeaderLine } BlankLine .
URLLine = /* URL that starts with "https://" */ '\n' .
HeaderLine = /* HTTP Request header */ '\n' .
BlankLine = '\n' .
处理 4xx 错误代码:如果服务器返回任何 4xx 错误,go
命令将再次调用 GOAUTH
命令并将错误信息发送到标准输入。
调用时机:GOAUTH
命令在第一次 HTTPS 获取之前被调用,若服务器返回错误,命令会再次被触发并附加 URL 及 HTTP 响应。
与 GOPRIVATE
的区别:GOPRIVATE
用于指定哪些模块路径前缀应视为私有,并默认禁止通过代理或校验和数据库访问。GOAUTH
则提供认证机制,允许在访问私有模块时提供用户名和密码等认证信息。
其他
- 版本控制:
go build
命令现在根据版本控制系统标签和/或提交在编译的二进制文件中设置主模块的版本。可以使用-buildvcs=false
标志省略二进制文件中的版本控制信息。 - Toolchain 跟踪:新的
GODEBUG
设置toolchaintrace=1
可用于跟踪go
命令的工具链选择过程。 - Cgo 支持 C 函数的新注释以提高运行时性能:
#cgo noescape cFunctionName
告诉编译器传递给 C 函数cFunctionName
的内存不会逃逸。#cgo nocallback cFunctionName
告诉编译器 C 函数cFunctionName
不会回调任何 Go 函数。 - Vet:新增 tests 分析器,用于报告测试包中测试、模糊测试、基准测试和示例声明中的常见错误,例如名称格式错误、签名不正确或示例记录不存在的标识符。其中一些错误可能会导致测试无法运行。此分析器属于
go test
运行的分析器子集。 - 新的实验性
testing/synctest
包:提供对测试并发代码的支持。
Runtime 运行时更新
Go 1.24 对运行时进行了一系列关键优化,核心目标就是让你的 Go 代码跑得更快,占用更少资源。
性能提升:CPU 开销平均降低 2-3%
这次的优化并非某个单点突破,而是多个改进叠加带来的整体提升,包括:
- 全新 map 实现 —— 采用 Swiss Tables,大幅提升哈希表的查询和插入效率。
- 小对象内存分配优化 —— 降低不必要的内存占用和分配开销。
- 改进运行时互斥锁实现 —— 提高多线程竞争时的稳定性,减少性能损失。
如果需要回退到旧的实现,可以使用以下编译选项:
GOEXPERIMENT=noswissmap # 关闭新 map 实现
GOEXPERIMENT=nospinbitmutex # 关闭新的互斥锁优化
更智能的垃圾回收与对象清理
新增 runtime.AddCleanup
,比 runtime.SetFinalizer
更灵活、更高效,避免了以往 SetFinalizer
可能导致的错误使用方式。
引入全新 weak 包,支持弱指针
Go 终于支持弱指针了!全新 weak
包允许开发者更高效地管理缓存、唯一值池等场景,避免无谓的内存占用,提高内存回收效率。
部分值得重点关注的标准库更新
Go 1.24 标准库引入了多项更新和改进。以下是标准库中一些值得注意的更改:
os.Root 限制目录访问
Go 1.24.1 引入了全新的 os.Root
类型,使开发者可以在指定目录内安全地执行文件系统操作,防止对根目录之外的文件进行访问。
os.Root
允许你限制文件操作范围,仅限于某个特定的目录树。所有通过 Root
进行的文件操作(如创建、读取、删除等)都只能作用于设定的根目录内。如果尝试访问该目录之外的文件或路径,Go 运行时会返回错误,从而增强安全性,防止意外或恶意的文件访问。
以下示例展示了如何使用 os.Root
限制文件访问范围:
package main
import (
"fmt"
"os"
)
func main() {
// 设定 /tmp 作为受限根目录
root, err := os.OpenRoot("/tmp")
if err != nil {
fmt.Println("打开根目录失败:", err)
return
}
defer root.Close()
// 在 /tmp 目录下创建 test.txt 文件
file, err := root.Create("test.txt")
if err != nil {
fmt.Println("创建文件失败:", err)
return
}
defer file.Close()
// 尝试访问根目录外的 /etc/passwd,会返回错误
_, err = root.Stat("/etc/passwd")
if err != nil {
fmt.Println("无法访问文件:", err) // 输出:stat /etc/passwd: no such file or directory
}
}
关键特性:
- 目录隔离:所有文件操作受限于
os.Root
设定的根目录,确保安全性。 - 避免路径穿越:防止访问
../
或绝对路径来绕过目录限制。 - 兼容常见文件操作:支持创建、删除、读取文件等常见操作,但仅限于设定的根目录内。
这一新特性提供了更安全的文件访问方式,适用于沙盒环境、受限存储等应用场景。
基准测试新增 Loop 方法
testing.B
结构体中新增了 Loop
方法,它提供了一种更加高效和更少出错的方式来进行基准测试迭代,替代了以前常用的 b.N
循环结构。主要有以下特点:
1. 简洁的结构:
你可以在基准测试中像这样使用 Loop
:
func Benchmark(b *testing.B) {
// 设置工作
for b.Loop() {
// 需要测量的代码
}
// 清理工作
}
2. 返回值:
Loop
方法会返回一个布尔值。只要基准测试还需要继续,它返回 true
,当返回 false
时,计时器停止,这样就不会测量到清理代码的时间。
3. 自动管理计时器:
Loop
方法会在第一次调用时重置基准测试的计时器,确保之前的设置时间不计入测量中。当返回 false
时,它会停止计时器,避免清理步骤被计入测试时间。
4. 防止编译器优化:
通过使用 for b.Loop()
循环,编译器不会优化掉循环体中的函数调用。这意味着即使编译器发现基准测试的结果没有被使用,它也不会跳过循环体的执行。需要注意的是,循环体内部的代码必须保持这种形式,其他部分的函数调用仍然可能会被优化掉。
5. 迭代次数:
在 Loop
返回 false
后,b.N
会包含实际执行的迭代次数,你可以根据 b.N
来计算其他的基准指标。
6. 优势:
- 精确的执行:基准测试只会执行一次指定次数的测试,避免了昂贵的设置和清理步骤被多次重复执行。
- 防止优化:确保每次测试都能完整执行,防止编译器优化掉不必要的部分。
注意事项:
基准测试应该选择使用 Loop
或者依赖 b.N
循环,但两者不能同时使用。Loop
会自动管理计时器并确保每次执行时只运行一次测试,而基于 b.N
的方法则会多次执行基准测试,包括相关的设置和清理。
weak 弱指针
Go 1.24 引入的 weak
包提供了一种创建弱指针的机制,它允许你安全地引用内存,而不会阻止垃圾回收器回收内存。可以把弱指针想象成一种特殊的指针,它“弱”到不会影响对象的生命周期。
弱指针是什么?
弱指针是指向某个值的指针,但与普通指针不同的是,垃圾回收器不会因为存在弱指针就认为该对象还在使用中。换句话说,即使有弱指针指向某个对象,只要没有其他“强”引用(即普通指针)指向它,该对象仍然可以被回收。
弱指针有什么作用?
弱指针主要用于以下几个方面:
- 实现缓存:可以缓存一些对象,但不希望这些对象一直占用内存。使用弱指针,当系统内存紧张时,这些缓存的对象可以被垃圾回收器自动清理掉。
- 规范化映射:确保对于某个值只有一个实例。比如字符串池,可以避免创建大量重复的字符串对象,节省内存。
- 生命周期管理:协调不同对象之间的依赖关系。例如,对象 B 依赖于对象 A,当 A 被回收时,自动清理掉 B。这可以避免悬挂对象,减少内存泄漏的风险。
使用弱指针的主要目的是避免内存泄漏。如果两个或多个对象相互引用,形成循环引用,那么垃圾回收器可能无法判断这些对象是否还在使用中,导致它们一直占用内存。弱指针可以打破这种循环引用,允许垃圾回收器回收不再需要的对象,从而防止内存泄漏。
Golang 中如何使用弱指针?
1. 创建弱指针:
使用 weak.Make[T](ptr *T)
函数可以从一个普通指针创建一个弱指针。
import "weak"
obj := new(int)
weakPtr := weak.Make(obj)
2. 访问弱指针指向的值:
使用弱指针的 Value()
方法可以获取原始指针。如果原始指针指向的对象已经被垃圾回收器回收,Value()
方法会返回 nil
。
需要注意的是,Pointer.Value
不保证最终会返回 nil
。Pointer.Value
可能会在对象变得不可达时立即返回 nil
。
ptr := weakPtr.Value()
if ptr != nil {
// 对象仍然有效
println(*ptr)
} else {
// 对象已被回收
println("Object has been reclaimed")
}
具体用法示例:
package main
import (
"fmt"
"runtime"
"weak"
)
func main() {
// 创建一个普通指针
obj := new(int)
*obj = 42
// 从普通指针创建一个弱指针
weakPtr := weak.Make(obj)
// 访问弱指针指向的值
ptr := weakPtr.Value()
if ptr != nil {
fmt.Println("Value:", *ptr)
} else {
fmt.Println("Object has been reclaimed")
}
// 移除所有对 obj 的强引用
obj = nil
// 强制执行垃圾回收
runtime.GC()
// 再次访问弱指针指向的值
ptr = weakPtr.Value()
if ptr != nil {
fmt.Println("Value:", *ptr)
} else {
fmt.Println("Object has been reclaimed") // 输出: Object has been reclaimed
}
}
注意事项
- 全局变量和可达对象:存储在全局变量中,或者可以通过从全局变量追踪指针找到的值是可达的。这意味着它们的弱指针可能不会变为
nil
。 - 函数参数和接收器:函数参数或接收器可能会在函数最后一次提到它时变得不可达。
runtime.KeepAlive
:为了确保Pointer.Value
不返回nil
,在对象必须保持可达的最后一点之后,将指向该对象的指针传递给runtime.KeepAlive
函数。- 空间优化:由于
Pointer.Value
不保证最终会返回nil
,即使在对象不再被引用之后,运行时也允许执行空间节省优化,将对象批量处理到一个分配槽中。如果一个未被引用的对象与一个被引用的对象始终存在于同一个批次中,则该对象的弱指针可能永远不会变为nil
。
encoding/json 功能增强
在 Go 1.24 中 encoding/json
包有一些更新和改进,主要涉及到如何处理结构体字段的零值以及一些增强的错误信息。
新增 omitzero 标签选项
在结构体的 JSON 标签中,Go 语言新增了 omitzero
选项。这个选项的作用是:当字段的值为零值时,自动忽略该字段。这和之前的 omitempty
标签有些相似,但是有一些重要的区别。
在 Go 语言中,零值是指未显式初始化的变量所默认赋予的值。不同类型的零值如下:
- 布尔值:
false
- 整数、浮点数:
0
- 字符串:
""
(空字符串) - 指针、函数、接口、切片、通道、映射:
nil
time.Time
:1970-01-01 00:00:00 +0000 UTC
这种零值行为是 Go 的一种设计理念,确保变量在声明时具有一个合理的默认值,避免未初始化的变量。
omitzero 的具体行为:
- 如果结构体字段的值是零值(比如数字为 0,布尔值为 false,字符串为空等),
omitzero
会让该字段在 JSON 编码时被省略。 - 重要的是,如果字段的类型有
IsZero()
方法,那么omitzero
会调用这个方法来判断是否为零值。否则,字段会被认为是其类型的零值(例如,0
对于整数,""
对于字符串,nil
对于指针等)。 omitzero
可以正确地忽略零值的time.Time
类型,而omitempty
无法做到这一点。时间类型的零值是January 1, year 1, 00:00:00 UTC
,这个时间通常不会出现在实际应用中,但omitzero
可以帮助你避免在 JSON 输出中包含这个零值。
UnmarshalTypeError.Field 包含更详细的错误信息
在 JSON 解码时,如果遇到类型不匹配的情况,会返回一个 UnmarshalTypeError
错误。这个错误现在包含了更多的细节信息,特别是对于嵌套结构体的错误,Field
字段会提供结构体路径,帮助开发者更容易定位错误。
strings 和 bytes 新增返回迭代器的函数
在 Go 1.24 中,strings
包新增了多个返回迭代器的函数。这些函数返回的是一个迭代器对象,它是基于 iter.Seq
类型的,能够逐个生成子字符串,而不需要一次性构建整个结果的切片。这种按需生成字符串片段的方式,有几个明显的优点:
- 内存效率高:由于每次只生成一个片段,避免了将所有拆分结果加载到内存中,特别适合处理大字符串。
- 性能优化:可以按需处理数据,在需要遍历大量数据时,不必一次性创建并存储所有拆分结果,减少了内存的占用和复制开销。
- 更灵活的迭代处理:迭代器适合在遍历字符串时进行逐个处理,而无需关心所有数据是否已经加载完毕,适合流式处理或懒加载场景。
以下是 Go 1.24 中新增的主要迭代器方法,它们都基于 iter.Seq
,返回一个可以逐个获取字符串片段的迭代器:
Lines(s string)
:按行返回字符串的迭代器。每次返回一个包含换行符的字符串,直到所有行都被遍历完。如果字符串没有换行符,最后一行不会包含换行符。SplitSeq(s, sep string)
:按照指定的分隔符sep
将字符串拆分,并返回一个迭代器。每次迭代返回一个被分隔出来的子字符串,直到整个字符串被拆分完毕。SplitAfterSeq(s, sep string)
:与SplitSeq
类似,不过返回的每个子字符串包含分隔符本身,即每次返回的片段会包含该分隔符。FieldsSeq(s string)
:按空白字符(如空格、制表符、换行符等)拆分字符串,返回一个迭代器。每次返回一个子字符串,直到字符串中所有的空白字符都被跳过。FieldsFuncSeq(s string, f func(rune) bool)
:根据自定义的函数f
来判断是否应拆分字符串。f
接受每个字符并返回一个布尔值,如果返回true
,则在该字符处拆分字符串。
另外,bytes
包也新增了以上这些返回迭代器的方法。
sync.Map 获得性能优化
在 Go 1.24 版本中,sync.Map 的实现做了一些优化,主要是提升了性能,特别是在修改映射时。如果你修改的键不重叠,性能提升更为明显。简单来说,修改大规模的 sync.Map 时,不同的键之间的操作不太会互相干扰,竞争的情况大大减少了。而且,以前在负载较重时,需要一定时间来“适应”并达到低竞争的状态,现在则不需要了,效率直接上升。
Go 提供了一个方法来切换回旧的实现。可以通过设置环境变量 GOEXPERIMENT=nosynchashtriemap
来回退到旧的 sync.Map 实现。
其他包的调整
- archive:
archive/zip
和archive/tar
中的(*Writer).AddFS
实现现在为空目录写入目录头。 - crypto/aes:
NewCipher
返回的值不再实现NewCTR
、NewGCM
、NewCBCEncrypter
和NewCBCDecrypter
方法。 - crypto/cipher:新的
NewGCMWithRandomNonce
函数返回一个通过在 Seal 期间生成随机 nonce 并将其前置到密文来实现 AES-GCM 的 AEAD。NewOFB
,NewCFBEncrypter
, 和NewCFBDecrypter
现在已弃用。 - crypto/ecdsa:如果随机源为 nil,
PrivateKey.Sign
现在根据 RFC 6979 生成确定性签名。 - crypto/md5:
md5.New
返回的值现在也实现了encoding.BinaryAppender
接口。 - crypto/rand:
Read
函数现在保证不会失败。新的Text
函数可用于生成加密安全的随机文本字符串。 - crypto/rsa:如果请求的密钥小于 1024 位,
GenerateKey
现在返回一个错误。 - crypto/sha1:
sha1.New
返回的值现在也实现了encoding.BinaryAppender
接口。 - crypto/sha256:
sha256.New
和sha256.New224
返回的值现在也实现了encoding.BinaryAppender
接口。 - crypto/sha512:
sha512.New
,sha512.New384
,sha512.New512_224
和sha512.New512_256
返回的值现在也实现了encoding.BinaryAppender
接口。 - crypto/subtle:新的
WithDataIndependentTiming
函数允许用户运行一个启用了架构特定功能的函数,这些功能保证特定指令是数据值时间不变的。 - crypto/tls:TLS 服务器现在支持加密客户端 Hello (ECH)。
- crypto/x509:
x509sha1
GODEBUG 设置已删除。Certificate.Verify
不再支持基于 SHA-1 的签名。 - debug/elf:
debug/elf
包添加了对处理动态 ELF (Executable and Linkable Format) 文件中符号版本的支持。 - encoding:引入了两个新接口
TextAppender
和BinaryAppender
,用于将对象的文本或二进制表示形式附加到字节切片。 - go/types:所有
go/types
数据结构现在也具有返回迭代器的方法。 - hash/adler32:
New
返回的值现在也实现了encoding.BinaryAppender
接口。 - hash/crc32:
New
和NewIEEE
返回的值现在也实现了encoding.BinaryAppender
接口。 - hash/crc64:
New
返回的值现在也实现了encoding.BinaryAppender
接口。 - hash/fnv:
New32
,New32a
,New64
,New64a
,New128
和New128a
返回的值现在也实现了encoding.BinaryAppender
接口。 - hash/maphash:新的
Comparable
和WriteComparable
函数可以计算任何可比较值的哈希值。 - log/slog:新的
DiscardHandler
是一个从不启用并且总是丢弃其输出的处理程序。 - math/big:
Float
,Int
和Rat
现在实现了encoding.TextAppender
接口。 - math/rand:调用已弃用的顶级
Seed
函数不再有任何效果。 - math/rand/v2:
ChaCha8
和PCG
现在实现了encoding.BinaryAppender
接口。 - net:
ListenConfig
现在默认在支持它的系统上使用 MPTCP (目前仅在 Linux 上)。 - net/http:
Transport
对响应请求收到的 1xx 信息响应的限制已更改。 - net/netip:
Addr
,AddrPort
和Prefix
现在实现了encoding.BinaryAppender
和encoding.TextAppender
接口。 - net/url:
URL
现在也实现了encoding.BinaryAppender
接口。 - os/user:在 Windows 上,
Current
现在可以在 Windows Nano Server 中使用。 - regexp:
Regexp
现在实现了encoding.TextAppender
接口。 - runtime:
GOROOT
函数现在已弃用。 - strings:
strings
包添加了多个使用迭代器的函数 (同bytes
包)。 - sync:
sync.Map
的实现已更改,提高了性能,尤其是在 map 修改方面。 - testing:新的
T.Context
和B.Context
方法返回一个在测试完成后并在测试清理函数运行之前取消的上下文。新的T.Chdir
和B.Chdir
方法可用于更改测试或基准测试期间的工作目录。 - text/template:模板现在支持 range-over-func 和 range-over-int。
- time:
Time
现在实现了encoding.BinaryAppender
和encoding.TextAppender
接口。
结语
Go 1.24 发布有些天了,今天详细了解了下,确实带来了许多有用的新功能和改进,包括对泛型类型别名的完全支持、新的工具链功能、运行时性能改进以及标准库的增强功能。这些更改使 Go 成为一种更强大、更灵活和更高效的编程语言。
Go1.24 我已升级,线上 go 服务也已更新,新版本这些优化,尤其是性能上的提升,诱惑力实在太大。你升级了没?