Go 1.26 新特性导览

 提示:转载请注明原文链接

 本文链接:https://360us.net/article/110.html

Go 1.26 新特性导览

Go 1.26 将于 2026 年 2 月正式发布,现在正是探索新特性的绝佳时机。官方发布的更新日志较为枯燥,因此我准备了一个交互式版本,通过大量示例展示具体变化和新行为。

本文基于 Go 作者团队的官方发布说明及 Go 源代码编写,遵循 BSD-3-Clause 许可证。本文并非详尽无遗的清单,请参阅官方发布说明以获取完整信息。

文中为各项特性提供了文档(𝗗)、提案(𝗣)、提交记录(𝗖𝗟)和作者(𝗔)的链接。建议查阅这些资料以了解设计动机、使用方式和实现细节。部分特性我还撰写了专门指南(𝗚)。

为保持简洁,示例中常省略错误处理。切勿在生产环境中照搬此做法


new(expr):支持表达式参数

过去,new 内建函数只能用于类型:

p := new(int)
*p = 42
fmt.Println(*p)

现在,它也可以接受表达式作为参数:

// 创建一个值为 42 的 int 变量的指针
p := new(42)
fmt.Println(*p)

若参数 expr 的类型为 T,则 new(expr) 会分配一个类型为 T 的变量,将其初始化为 expr 的值,并返回其地址(类型为 *T)。

该特性在使用结构体指针字段表示 JSON 或 Protobuf 中的可选值时尤为实用:

type Cat struct {
    Name string `json:"name"`
    Fed  *bool  `json:"is_fed"` // 猫是否被喂食?你永远无法确定
}

cat := Cat{Name: "Mittens", Fed: new(true)}
data, _ := json.Marshal(cat)
fmt.Println(string(data))

new 还可用于复合字面量:

s := new([]int{11, 12, 13})
fmt.Println(*s)

type Person struct{ name string }
p := new(Person{name: "alice"})
fmt.Println(*p)

甚至可用于函数调用:

f := func() string { return "go" }
p := new(f())
fmt.Println(*p)

但传入 nil 仍不被允许:

p := new(nil)
// 编译错误

📚 规范 • 💡 提案 #45624 • 🔧 CL 704935 等 • 👤 Alan Donovan


类型安全的错误检查:errors.AsType

新增的 errors.AsTypeerrors.As 的泛型版本:

// Go 1.13+
func As(err error, target any) bool
// Go 1.26+
func AsType[E error](err error) (E, bool)

它类型安全且更易使用:

// 使用 errors.As
var target *AppError
if errors.As(err, &target) {
    fmt.Println("应用错误:", target)
}

// 使用 errors.AsType
if target, ok := errors.AsType[*AppError](err); ok {
    fmt.Println("应用错误:", target)
}

AsType 在检查多种错误类型时特别方便,代码更简洁,且错误变量作用域限定在 if 块内:

if connErr, ok := errors.AsType[*net.OpError](err); ok {
    fmt.Println("网络操作失败:", connErr.Op)
} else if dnsErr, ok := errors.AsType[*net.DNSError](err); ok {
    fmt.Println("DNS 解析失败:", dnsErr.Name)
} else {
    fmt.Println("未知错误")
}

errors.As 使用反射,若使用不当(如传入非指针或未实现 error 接口的类型)会导致运行时 panic:

// 错误用法:target 不是指针
var target AppError
if errors.As(err, &target) { ... } // 可能 panic

AsType 在编译期即可捕获此类错误:

// 编译错误:AppError 不是指针类型
if target, ok := errors.AsType[AppError](err); ok { ... }

性能方面,AsType 不使用反射,执行更快、内存分配更少:

BenchmarkAs-8        12606744    95.62 ns/op    40 B/op    2 allocs/op
BenchmarkAsType-8    37961869    30.26 ns/op    24 B/op    1 allocs/op

由于 AsType 能完全替代 As推荐在新代码中直接使用 AsType

📚 errors.AsType • 💡 提案 #51945 • 🔧 CL 707235 • 👤 Julien Cretel


“绿茶”垃圾回收器(Green Tea GC)

Go 1.26 默认启用了新的垃圾回收器(“绿茶”GC,最初在 1.25 中作为实验性功能引入),旨在提升多核现代计算机上的内存管理效率。

动机

传统 GC 将对象视为图中的节点、指针视为边,不考虑对象在物理内存中的布局。扫描时频繁跳转到远端内存地址,导致大量 CPU 缓存未命中。超过 35% 的扫描时间浪费在等待内存数据上,且随着 CPU 核心数增加,问题愈发严重。

实现

“绿茶”GC 从“处理器中心”转向“内存感知”。它不再逐个扫描对象,而是以 8 KiB 的连续内存块(称为 span) 为单位进行扫描,重点优化 512 字节以下的小对象(因其最常见且最难高效扫描)。

每个 span 根据其大小类别(size class)划分为等长槽位,仅存放同尺寸对象。例如,32 字节大小类别的 span 会被划分为多个 32 字节槽位,对象起始地址对齐槽位开头。这种固定布局使 GC 可通过简单地址运算快速定位对象元数据,无需逐个检查对象大小。

当发现需扫描的对象时,GC 先标记其在 span 中的位置,暂不立即扫描,而是等待同一 span 中积累多个待扫描对象后批量处理,避免重复访问同一内存区域。

为更好利用多核,GC 工作线程采用任务窃取机制:每个线程拥有本地 span 队列,空闲时可从其他繁忙线程队列中“窃取”任务。这种去中心化设计消除了全局任务队列瓶颈,减少核心间竞争。

在 amd64 架构上,“绿茶”GC 还利用向量化 CPU 指令批量处理内存 span(当对象数量足够时)。

性能

Go 团队预计,在重度依赖 GC 的真实程序中,GC 开销可降低 10–40%;在支持 AVX-512 的 CPU(如 Intel Ice Lake、AMD Zen 4+)上,还可额外降低 10%

⚠️ 目前尚无公开的最新版“绿茶”GC 基准测试结果,我也未能构建有效的合成基准测试。

该 GC 默认启用。如需使用旧版 GC,可在构建时设置 GOEXPERIMENT=nogreenteagc(该选项预计在 Go 1.27 中移除)。

💡 提案 #73581 • 👤 Michael Knyszek


更快的 cgo 与系统调用

Go 运行时中,处理器(P) 是执行 goroutine(G)所需的资源。线程(M)必须先获取 P 才能运行 G。

P 有多种状态:_Prunning(运行中)、_Pidle(空闲)、_Pgcstop(GC 暂停)等。

此前,当 goroutine 执行系统调用或 cgo 调用时,P 会进入 _Psyscall 状态。Go 1.26 移除了该状态,改为直接检查绑定到 P 的 goroutine 是否处于系统调用中。

此举减少了运行时开销,简化了 cgo 和系统调用的代码路径。官方称 cgo 运行时开销降低 30%,提交记录显示性能提升 18%

CgoCall-64: 43.69n → 35.83n (-17.99%)

我在 Apple M1 上的本地测试结果更显著:

CgoCall-8: 28.55n → 19.02n (-33.40%)
CgoCallWithCallback-8: 72.76n → 57.38n (-21.14%)
几何平均: -27.53%

系统调用也有提升:

Syscall-8: 195.6n → 178.1n (-8.95%)

🔧 CL 646198 • 👤 Michael Knyszek


更快的内存分配

Go 运行时现在为 1–512 字节的小对象提供了专用的内存分配函数。通过跳转表(jump table) 快速选择对应尺寸的分配器,而非使用单一通用实现。

📝 注:尽管发布说明称“编译器将生成对尺寸专用分配例程的调用”,但实际上编译器仍调用通用 mallocgc 函数,由其在运行时分发至专用分配器。

该优化使小对象分配成本最高降低 30%,整体分配密集型程序预计提升 ~1%

我的本地基准测试(Apple M1)结果如下:

Alloc1-8:   8.190n → 6.594n (-19.48%)
Alloc8-8:   8.648n → 7.522n (-13.02%)
Alloc64-8:  15.70n → 12.57n (-19.88%)
Alloc128-8: 56.80n → 17.56n (-69.08%)
Alloc512-8: 81.50n → 55.24n (-32.23%)
几何平均: -34.83%

该优化默认启用。可通过 GOEXPERIMENT=nosizespecializedmalloc 禁用(预计 Go 1.27 移除)。

🔧 CL 665835 • 👤 Michael Matloob


向量化操作(实验性)

新增 simd/archsimd 包提供对架构特定向量化指令(SIMD)的底层访问,目前仅支持 amd64

因不同 CPU 的 SIMD 指令差异巨大,Go 团队选择先提供低层、架构专用 API,让高级用户能在主流服务器平台(amd64)上立即使用 SIMD。

包中定义了与硬件寄存器匹配的向量类型,如 Int8x16(128 位,16 个 8 位整数)、Float64x8(512 位,8 个 64 位浮点数),支持 128/256/512 位宽向量。

操作以方法形式定义,通常零开销映射到硬件指令。例如,使用 SIMD 加法:

func Add(a, b []float32) []float32 {
    if len(a) != len(b) { panic("长度不同") }
    if !archsimd.X86.AVX512() { return fallbackAdd(a, b) }

    res := make([]float32, len(a))
    n := len(a)
    i := 0

    // SIMD 循环:每次处理 16 个元素
    for i <= n-16 {
        va := archsimd.LoadFloat32x16Slice(a[i:i+16])
        vb := archsimd.LoadFloat32x16Slice(b[i:i+16])
        vSum := va.Add(vb) // 对应 VADDPS 汇编指令
        vSum.StoreSlice(res[i:i+16])
        i += 16
    }

    // 标量尾部:处理剩余元素
    for ; i < n; i++ { res[i] = a[i] + b[i] }
    return res
}

常见操作包括:

  • 加载/存储Load / Store
  • 算术Add, Sub, Mul, Div, DotProduct
  • 位运算And, Or, Not, Xor, Shift
  • 比较Equal, Greater, Less, Min, Max
  • 转换As, SaturateTo, TruncateTo
  • 掩码Compress, Masked, Merge
  • 重排Permute

⚠️ 该包仅使用 AVX 指令,不包含 SSE。

基准测试(AMD EPYC)显示 SIMD 版本吞吐量提升数十倍:

AddSIMD/1m-2: 127351 MB/s vs AddPlain/1m-2: 11932 MB/s

该包为实验性,需通过 GOEXPERIMENT=simd 启用。

📚 simd/archsimd • 💡 提案 #73787 • 🔧 多个 CL • 👤 Junyang Shao 等


安全模式(Secret Mode,实验性)

加密协议(如 WireGuard/TLS)要求前向保密(forward secrecy):即使长期密钥泄露,历史会话也不应被解密。这要求临时密钥(ephemeral key) 在握手完成后立即从内存清除。

Go 运行时不保证内存何时清零,敏感数据可能残留在堆或栈中(如 core dump)。开发者常需用反射等不可靠“黑科技”手动清零。

Go 1.26 引入 runtime/secret 包解决此问题。secret.Do(func()) 可在安全模式下执行函数,结束后立即清零其使用的寄存器和栈;堆分配则在 GC 判定不可达后清零。

secret.Do(func() {
    // 生成临时密钥并完成会话协商
})

示例:安全派生会话密钥

func DeriveSessionKey(peerPublicKey *ecdh.PublicKey) (*ecdh.PublicKey, []byte, error) {
    var pubKey *ecdh.PublicKey
    var sessionKey []byte
    var err error

    secret.Do(func() {
        // 1. 生成临时私钥(高度敏感!)
        privKey, e := ecdh.P256().GenerateKey(rand.Reader)
        if e != nil { err = e; return }

        // 2. 计算共享密钥(同样高度敏感!)
        sharedSecret, e := privKey.ECDH(peerPublicKey)
        if e != nil { err = e; return }

        // 3. 派生最终会话密钥
        sessionKey = performHKDF(sharedSecret)
        pubKey = privKey.PublicKey()
    })

    return pubKey, sessionKey, err // “配方”已被销毁
}

此处临时私钥和共享密钥如同“有毒废料”——必要但危险。若残留在内存中,攻击者可利用其重放解密历史流量。

secret.Do 确保这些中间值在会话密钥生成后永久销毁,即使未来服务器被攻破,该会话也无法被解密,从而保障前向保密。

⚠️ 当前仅支持 Linux(amd64/arm64)。不支持平台直接调用函数。函数内启动 goroutine 会 panic(Go 1.27 修复)。

该包主要面向加密库开发者,普通应用应使用已集成 secret.Do 的高层库。

需通过 GOEXPERIMENT=runtimesecret 启用。

📚 runtime/secret • 💡 提案 #21865 • 🔧 CL 704615 • 👤 Daniel Morsing


无 Reader 的加密 API

现有加密 API(如 ecdsa.GenerateKeyrand.Prime)常接受 io.Reader 作为随机源:

key, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
prim, _ := rand.Prime(rand.Reader, 64)

但 API 未承诺如何使用 reader 中的字节。底层算法变更可能导致读取序列/数量变化,若应用依赖特定行为,升级后可能出错。

Go 团队采取大胆方案:大多数加密 API 现在忽略 io.Reader 参数,始终使用系统随机源(crypto/internal/sysrand.Read

// reader 参数不再使用,可传 nil
key, _ := ecdsa.GenerateKey(elliptic.P256(), nil)
prim, _ := rand.Prime(nil, 64)

受影响的子包包括:

  • crypto/dsa
  • crypto/ecdh
  • crypto/ecdsa
  • crypto/rand
  • crypto/rsa

⚠️ ed25519.GenerateKey(rand) 仍使用提供的 reader;若为 nil,则使用内部安全随机源(非 crypto/rand.Reader)。

为支持确定性测试,新增 testing/cryptotest 包:

func Test(t *testing.T) {
    cryptotest.SetGlobalRandom(t, 42) // 设置全局确定性随机源

    p1, _ := rand.Prime(nil, 32)
    // 所有测试运行将生成相同数字
}

SetGlobalRandom 影响 crypto/rand 及所有 crypto/* 包的隐式随机源。

可通过 GODEBUG=cryptocustomrand=1 恢复旧行为(未来版本将移除)。

📚 testing/cryptotest • 💡 提案 #70942 • 🔧 CL 724480 • 👤 Filippo Valsorda 等


Goroutine 泄漏分析(实验性)

Goroutine 泄漏指 goroutine 因通道等同步原语无限阻塞,而程序其他部分仍在运行。例如:

func leak() <-chan int {
    out := make(chan int)
    go func() { out <- 42 }() // 若无人读取,则泄漏
    return out
}

func main() { leak() } // 内部 goroutine 永久阻塞

泄漏不像死锁会 panic,也长期缺乏工具检测。

Go 1.24 引入 synctest 包用于测试时检测泄漏。Go 1.26 新增实验性 goroutineleak pprof 分析器,用于生产环境报告泄漏:

func main() {
    prof := pprof.Lookup("goroutineleak")
    leak()
    time.Sleep(50 * time.Millisecond)
    prof.WriteTo(os.Stdout, 2) // 输出泄漏的 goroutine 栈跟踪
}

其实现原理:利用 GC 标记阶段,从可运行 goroutine 出发,标记所有可达的同步对象及等待其上的阻塞 goroutine。剩余无法到达的阻塞 goroutine 即视为泄漏。

📚 runtime/pprof • 📘 泄漏检测指南 • 💡 提案 #74609 • 🔧 CL 688335 • 👤 Vlad Saioc

需通过 GOEXPERIMENT=goroutineleakprofile 启用,并可通过 /debug/pprof/goroutineleak HTTP 端点访问。


Goroutine 指标

runtime/metrics 新增指标,提供 goroutine 调度的细粒度洞察:

  • 程序启动以来创建的 goroutine 总数
  • 各状态 goroutine 数量
  • 活跃线程数

完整列表:

  • /sched/goroutines-created:创建总数
  • /sched/goroutines/not-in-go:阻塞于系统调用/cgo 的 goroutine
  • /sched/goroutines/runnable:就绪但未运行的 goroutine
  • /sched/goroutines/running:正在运行的 goroutine
  • /sched/goroutines/waiting:等待 I/O 或同步原语的 goroutine
  • /sched/threads/total:Go 运行时拥有的活跃线程数

这些指标可关联生产问题:

  • waiting 持续增长 → 锁竞争
  • not-in-go 过高 → goroutine 卡在 syscall/cgo
  • runnable 积压 → CPU 不足

通过 metrics.Read 读取:

sample := []metrics.Sample{{Name: "/sched/goroutines/running:goroutines"}}
metrics.Read(sample)
fmt.Printf("Running: %v\n", sample[0].Value.Uint64())

📚 runtime/metrics • 💡 提案 #15490 • 🔧 多个 CL • 👤 Michael Knyszek


反射迭代器

reflect 包新增迭代器方法:

  • Type.Fields() / Type.Methods():遍历结构体字段/方法
  • Type.Ins() / Type.Outs():遍历函数参数/返回值
  • Value.Fields() / Value.Methods():遍历值的字段/方法(同时返回类型信息和值)
// 遍历 http.Client 字段
typ := reflect.TypeFor[http.Client]()
for f := range typ.Fields() {
    fmt.Println(f.Name, f.Type)
}

// 遍历值的字段(含值)
client := &http.Client{}
val := reflect.ValueOf(client)
for f, v := range val.Elem().Fields() {
    fmt.Printf("- %s (%s)\n", f.Name, v.Kind())
}

相比旧版 for i := 0; i < typ.NumField(); i++ 更简洁。

📚 reflect • 💡 提案 #66631 • 🔧 CL 707356 • 👤 Quentin Quaadgras


Peek into a buffer

bytes.Buffer 新增 Peek(n) 方法,返回缓冲区前 n 字节但不移动读取位置:

buf := bytes.NewBufferString("I love bytes")
sample, _ := buf.Peek(1) // "I"
buf.Next(2)              // 跳过 "I "
sample, _ = buf.Peek(4)  // "love"

若缓冲区不足 n 字节,返回 io.EOF

返回的切片指向缓冲区内存,在下次读写前有效。直接修改会影响后续读取:

buf := bytes.NewBufferString("car")
sample, _ := buf.Peek(3) // "car"
sample[2] = 't'          // 修改底层缓冲区
data, _ := buf.ReadBytes(0) // "cat"

📚 Buffer.Peek • 💡 提案 #73794 • 🔧 CL 674415 • 👤 Ilia Choly


进程句柄(Process Handle)

os.Process 内部在支持的操作系统(Linux 使用 pidfd,Windows 使用句柄)上使用进程句柄而非 PID,确保方法始终作用于同一进程(避免 PID 复用问题)。

Go 1.26 新增 Process.WithHandle 方法访问该句柄:

proc, _ := os.StartProcess("/bin/echo", []string{"hello"}, nil)
proc.WithHandle(func(handle uintptr) {
    fmt.Println("handle =", handle)
})

句柄在回调函数返回前保证有效(即使进程已终止)。仅支持 Linux 5.4+ 和 Windows,其他系统返回 os.ErrNoHandle

📚 Process.WithHandle • 💡 提案 #70352 • 🔧 CL 699615 • 👤 Kir Kolyshkin


信号作为上下文取消原因

signal.NotifyContext 返回的上下文被取消时,其 context.Cause(ctx) 现在会显示具体信号(此前仅显示 "context canceled"):

ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
// ...
fmt.Println("cause =", context.Cause(ctx)) // 输出 "interrupt"

返回类型 signal.signalError 基于字符串,仅提供信号的字符串表示,非 os.Signal 值。

📚 signal.NotifyContext • 🔧 CL 721700 • 👤 Filippo Valsorda


比较 IP 子网

netip.Prefix 新增 Compare 方法,便于排序 CIDR 前缀:

prefixes := []netip.Prefix{
    netip.MustParsePrefix("10.1.0.0/16"),
    netip.MustParsePrefix("203.0.113.0/24"),
    // ...
}
slices.SortFunc(prefixes, netip.Prefix.Compare)

排序规则:

  1. 有效性(无效 < 有效)
  2. 地址族(IPv4 < IPv6)
  3. 网络地址(10.0.0.0/16 < 10.1.0.0/16
  4. 前缀长度(/8 < /16
  5. 原始 IP(10.0.0.0/8 < 10.0.0.1/8

符合 Python netaddr.IPNetwork 和 IANA 标准。

📚 Prefix.Compare • 💡 提案 #61642 • 🔧 CL 700355 • 👤 database64128


支持上下文的拨号

net 包顶层函数(DialTCP 等)因早于 context.Context 设计,不支持取消。而 net.Dialer.DialContext 虽支持取消,但因地址解析和网络分发开销,效率较低

Go 1.26 为 net.Dialer 新增上下文感知的专用拨号方法DialTCPDialUDP 等,兼具专用函数的效率和 DialContext 的取消能力:

var d net.Dialer
raddr := netip.MustParseAddrPort("127.0.0.1:12345")
conn, err := d.DialTCP(ctx, "tcp", netip.AddrPort{}, raddr)

📚 net.Dialer • 💡 提案 #49097 • 🔧 CL 490975 • 👤 Michael Fraenkel


伪造 example.com

httptest.Server 的默认证书已包含 example.com。此前,Server.Client() 会因证书不受信任而拒绝连接真实 example.com

Go 1.26 起,Server.Client() 会将 example.com 及其子域名的请求重定向到测试服务器

srv := httptest.NewTLSServer(handler)
resp, _ := srv.Client().Get("https://example.com") // 实际请求测试服务器

📚 Server.Client • 🔧 CL 666855 • 👤 Sean Liao


优化 fmt.Errorf

此前,对纯字符串使用 fmt.Errorf("foo")errors.New("foo") 多分配内存。有人建议无格式化时改用 errors.New

Russ Cox 反对:“统一使用 fmt.Errorf 更简洁,无需根据参数切换函数。”

Go 1.26 优化后,fmt.Errorf 对非逃逸错误0 分配,逃逸错误1 分配,与 errors.New 持平。CPU 开销也大幅缩小(逃逸错误:64ns → 25ns vs 21ns)。

📚 fmt.Errorf • 🔧 CL 708836 • 👤 thepudds


优化 io.ReadAll

此前 io.ReadAll 在扩容结果切片时分配大量中间内存。新实现使用指数增长的中间切片,最后复制到精确大小的最终切片。

对 65KiB 输入,速度提升 2 倍,内存使用减半。最终切片容量更精确,避免长期持有无用内存。

📚 io.ReadAll • 🔧 CL 722500 • 👤 thepudds


多日志处理器(Multiple Log Handlers)

slog 包(Go 1.21 引入)新增 MultiHandler,可同时向多个目标(如 stdout 和文件)输出日志:

stdoutHandler := slog.NewTextHandler(os.Stdout, nil)
file, _ := os.OpenFile("/tmp/app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
fileHandler := slog.NewJSONHandler(file, nil)

multiHandler := slog.NewMultiHandler(stdoutHandler, fileHandler)
logger := slog.New(multiHandler)
logger.Info("login", slog.String("name", "whoami"))

MultiHandler 依次调用所有启用的处理器。若任一处理器返回错误,使用 errors.Join 合并所有错误。

📚 slog.MultiHandler • 💡 提案 #65954 • 🔧 CL 692237 • 👤 Jes Cok


测试产物(Test Artifacts)

测试或基准测试生成的文件(如日志、内存转储)对远程调试(如 CI)至关重要。

Go 1.26 新增 T.ArtifactDir()B.ArtifactDir()F.ArtifactDir() 方法,返回测试专属目录:

func TestFunc(t *testing.T) {
    dir := t.ArtifactDir()
    logFile := filepath.Join(dir, "app.log")
    os.WriteFile(logFile, []byte("ERROR: Connection failed\n"), 0644)
}

使用 go test -artifacts 时,产物保存在 -outputdir 指定目录(默认当前目录)下的 _artifacts/ 子目录中。未指定 -artifacts 时,产物存于临时目录并在测试后删除。

每个测试/子测试有独立产物目录(同级而非嵌套)。

📚 T.ArtifactDir • 💡 提案 #71287 • 🔧 CL 696399 • 👤 Damien Neil


现代化的 go fix

go fix 命令曾是针对古老 Go 特性的重写工具集。Go 1.26 起,它基于 Go 分析框架(与 go vet 相同)重构。

  • go vet报告问题(修复建议不一定安全)
  • go fix现代化代码(修复始终安全,但不一定表示代码有问题)

用法:

go fix -diff .          # 显示补丁而非应用
go fix -forvar .        # 仅运行 forvar 分析器
go fix -omitzero=false . # 运行除 omitzero 外的所有分析器

示例:将循环替换为 slices.Contains

// 修复前
func find(s []int, x int) bool {
    for _, v := range s {
        if x == v { return true }
    }
    return false
}

// 修复后
func find(s []int, x int) bool {
    return slices.Contains(s, x)
}

📚 cmd/fix • 📘 go fix 指南 • 💡 提案 #71859 • 👤 Alan Donovan


总结

Go 1.26 是史上最大规模的发布,理由充分:

  • 实用更新:增强的 new、类型安全错误检查、goroutine 泄漏检测器
  • 性能提升:新 GC、更快的 cgo/内存分配、优化的 fmt.Errorf/io.ReadAll
  • 体验改进:多日志处理器、测试产物、现代化 go fix
  • 专业实验特性:SIMD 支持、前向保密安全模式

此外,Go 1.25 引入的实验性 json/v2 包仍在开发中,可通过 GOEXPERIMENT=jsonv2 启用。

总而言之,这是一次卓越的发布!

原文链接https://antonz.org/go-1-26/


本文链接:https://360us.net/article/110.html