Go 1.25 發行說明

Go 1.25 簡介

最新的 Go 版本 1.25 將於 2025 年 8 月 釋出,比 Go 1.24 晚六個月。其大部分更改都在工具鏈、執行時和庫的實現中。一如既往,此版本保持了 Go 1 的相容性承諾。我們預計幾乎所有 Go 程式都將繼續像以前一樣編譯和執行。

語言變化

Go 1.25 中沒有影響 Go 程式的語言更改。然而,在語言規範中,核心型別的概念已被刪除,取而代之的是專門的散文。有關更多資訊,請參閱相關的部落格文章

工具

Go 命令

go build -asan 選項現在預設為在程式退出時進行記憶體洩漏檢測。如果 C 分配的記憶體未釋放且未被 C 或 Go 分配的任何其他記憶體引用,則將報告錯誤。可以透過在執行程式時在環境中設定 ASAN_OPTIONS=detect_leaks=0 來停用這些新的錯誤報告。

Go 發行版將包含更少的預構建工具二進位制檔案。編譯器和連結器等核心工具鏈二進位制檔案仍將包含在內,但未透過構建或測試操作呼叫的工具將根據需要由 go tool 構建和執行。

新的 go.mod ignore 指令可用於指定 go 命令應忽略的目錄。當匹配包模式(如 all./...)時,go 命令將忽略這些目錄及其子目錄中的檔案,但它們仍將包含在模組 zip 檔案中。

新的 go doc -http 選項將啟動一個文件伺服器,顯示所請求物件的文件,並在瀏覽器視窗中開啟文件。

新的 go version -m -json 選項將列印給定 Go 二進位制檔案中嵌入的 runtime/debug.BuildInfo 結構的 JSON 編碼。

當使用 <meta name="go-import" content="root-path vcs repo-url subdir"> 語法解析模組路徑時,go 命令現在支援使用儲存庫的子目錄作為模組根的路徑,以指示 root-path 對應於具有版本控制系統 vcsrepo-urlsubdir

新的 work 包模式匹配工作(以前稱為主)模組中的所有包:模組模式下的單個工作模組或工作區模式下的工作區模組集。

當 go 命令更新 go.modgo.work 檔案中的 go 行時,它不再新增指定命令當前版本的工具鏈行。

Vet

go vet 命令包含新的分析器

  • hostport,它報告使用 fmt.Sprintf("%s:%d", host, port) 構造 net.Dial 地址,因為這些地址不適用於 IPv6;相反,它建議使用 net.JoinHostPort

執行時

容器感知 GOMAXPROCS

GOMAXPROCS 的預設行為已更改。在 Go 的早期版本中,GOMAXPROCS 預設為啟動時可用的邏輯 CPU 數量 (runtime.NumCPU)。Go 1.25 引入了兩項更改

  1. 在 Linux 上,執行時會考慮包含程序的 cgroup 的 CPU 頻寬限制(如果有)。如果 CPU 頻寬限制低於可用邏輯 CPU 的數量,GOMAXPROCS 將預設為較低的限制。在 Kubernetes 等容器執行時系統中,cgroup CPU 頻寬限制通常對應於“CPU 限制”選項。Go 執行時不考慮“CPU 請求”選項。

  2. 在所有作業系統上,如果可用邏輯 CPU 數量或 cgroup CPU 頻寬限制發生變化,執行時會定期更新 GOMAXPROCS

如果透過 GOMAXPROCS 環境變數或呼叫 runtime.GOMAXPROCS 手動設定 GOMAXPROCS,則這兩種行為都會自動停用。它們也可以分別透過 GODEBUG 設定 containermaxprocs=0updatemaxprocs=0 顯式停用。

為了支援讀取更新的 cgroup 限制,執行時將在程序生命週期內保留 cgroup 檔案的快取檔案描述符。

新的實驗性垃圾收集器

一個新的垃圾收集器現在作為實驗提供。該垃圾收集器的設計透過更好的區域性性和 CPU 可伸縮性,提高了標記和掃描小物件的效能。基準測試結果各不相同,但我們預計在大量使用垃圾收集器的實際程式中,垃圾收集開銷將減少 10-40%。

可以透過在構建時設定 GOEXPERIMENT=greenteagc 來啟用新的垃圾收集器。我們預計該設計將繼續發展和改進。為此,我們鼓勵 Go 開發人員嘗試並報告他們的經驗。有關設計和分享反饋的說明的更多詳細資訊,請參閱 GitHub 問題

跟蹤飛行記錄器

執行時執行跟蹤長期以來提供了一種強大但昂貴的方式來理解和除錯應用程式的低階行為。不幸的是,由於其大小和持續寫入執行跟蹤的成本,它們通常不適用於除錯罕見事件。

新的 runtime/trace.FlightRecorder API 提供了一種輕量級方式來捕獲執行時執行跟蹤,方法是持續將跟蹤記錄到記憶體環形緩衝區中。當發生重要事件時,程式可以呼叫 FlightRecorder.WriteTo 將跟蹤的最後幾秒快照到檔案中。這種方法透過使應用程式僅捕獲重要的跟蹤來生成更小的跟蹤。

FlightRecorder 捕獲的時間長度和資料量可以在 FlightRecorderConfig 中配置。

未處理恐慌輸出的更改

當程式由於未處理的恐慌(已恢復並重新恐慌)而退出時列印的訊息不再重複恐慌值文字。

以前,一個程式如果因 panic("PANIC") 而恐慌,恢復恐慌,然後以原始值重新恐慌,則會列印

panic: PANIC [recovered]
  panic: PANIC

該程式現在將列印

panic: PANIC [recovered, repanicked]

Linux 上的 VMA 名稱

在支援匿名虛擬記憶體區域 (VMA) 名稱 (CONFIG_ANON_VMA_NAME) 的 Linux 系統上,Go 執行時將使用有關其目的的上下文註釋匿名記憶體對映。例如,堆記憶體的 [anon: Go: heap]。這可以透過 GODEBUG 設定 decoratemappings=0 停用。

編譯器

nil 指標錯誤

此版本修復了 Go 1.21 中引入的編譯器錯誤,該錯誤可能錯誤地延遲 nil 指標檢查。像以下程式(以前錯誤地成功執行)現在將(正確地)因 nil-pointer 異常而恐慌

package main

import "os"

func main() {
    f, err := os.Open("nonExistentFile")
    name := f.Name()
    if err != nil {
        return
    }
    println(name)
}

此程式不正確,因為它在使用 os.Open 的結果之前檢查了錯誤。如果 err 不為 nil,則 f 結果可能為 nil,在這種情況下 f.Name() 應該恐慌。然而,在 Go 1.21 到 1.24 版本中,編譯器錯誤地將 nil 檢查延遲到錯誤檢查之*後*,導致程式成功執行,違反了 Go 規範。在 Go 1.25 中,它將不再成功執行。如果此更改影響您的程式碼,解決方案是將非 nil 錯誤檢查放在程式碼中更早的位置,最好是緊跟在生成錯誤的語句之後。

DWARF5 支援

Go 1.25 中的編譯器和連結器現在使用 DWARF 版本 5 生成除錯資訊。較新的 DWARF 版本減少了 Go 二進位制檔案中除錯資訊所需的空間,並減少了連結時間,特別是對於大型 Go 二進位制檔案。可以透過在構建時設定環境變數 GOEXPERIMENT=nodwarf5 來停用 DWARF 5 生成(此回退可能會在未來的 Go 版本中刪除)。

更快的切片

編譯器現在可以在更多情況下在堆疊上分配切片的後備儲存,從而提高效能。此更改有可能放大不正確 unsafe.Pointer 用法的影響,例如 問題 73199。為了跟蹤這些問題,可以使用 bisect 工具使用 -compile=variablemake 標誌查詢導致問題的分配。所有此類新的堆疊分配也可以使用 -gcflags=all=-d=variablemakehash=n 關閉。

連結器

連結器現在接受 -funcalign=N 命令列選項,該選項指定函式入口的對齊方式。預設值與平臺相關,在此版本中未更改。

標準庫

新的 testing/synctest 包

新的 testing/synctest 包提供了測試併發程式碼的支援。

Test 函式在隔離的“氣泡”中執行測試函式。在氣泡內,時間是虛擬化的:time 包函式在假時鐘上操作,如果氣泡中的所有 goroutine 都被阻塞,則時鐘會立即前進。

Wait 函式等待當前氣泡中的所有 goroutine 阻塞。

此包最初在 Go 1.24 中作為 GOEXPERIMENT=synctest 提供,API 略有不同。該實驗現在已全面推出。如果設定了 GOEXPERIMENT=synctest,舊 API 仍然存在,但將在 Go 1.26 中刪除。

新的實驗性 encoding/json/v2 包

Go 1.25 包含一個新的實驗性 JSON 實現,可以透過在構建時設定環境變數 GOEXPERIMENT=jsonv2 來啟用。

啟用後,兩個新包可用

此外,當啟用“jsonv2”GOEXPERIMENT 時

  • encoding/json 包使用新的 JSON 實現。編組和解組行為不受影響,但包函式返回的錯誤文字可能會更改。
  • encoding/json 包包含許多可用於配置編組器和解組器的新選項。

在許多場景下,新實現的效能顯著優於現有實現。通常,編碼效能在兩個實現之間是平等的,而解碼在新實現中則顯著更快。有關更詳細的分析,請參閱 github.com/go-json-experiment/jsonbench 儲存庫。

有關更多詳細資訊,請參閱提案問題

我們鼓勵 encoding/json 的使用者啟用 GOEXPERIMENT=jsonv2 來測試他們的程式,以幫助檢測新實現的任何相容性問題。

我們預計 encoding/json/v2 的設計將繼續發展。我們鼓勵開發人員嘗試新的 API 並在 提案問題上提供反饋。

對庫的微小更改

archive/tar

Writer.AddFS 實現現在支援為實現 io/fs.ReadLinkFS 的檔案系統提供符號連結。

encoding/asn1

UnmarshalUnmarshalWithParams 現在更一致地解析 ASN.1 型別 T61String 和 BMPString。這可能會導致以前接受的一些格式錯誤的編碼現在被拒絕。

crypto

MessageSigner 是一個新的簽名介面,可以由希望自行雜湊要簽名的訊息的簽名者實現。還引入了一個新函式 SignMessage,它嘗試將 Signer 介面升級為 MessageSigner,如果成功則使用 MessageSigner.SignMessage 方法,否則使用 Signer.Sign。當代碼希望同時支援 SignerMessageSigner 時,可以使用此功能。

程式啟動後更改 fips140 GODEBUG 設定現在是一個空操作。以前,它被記錄為不允許,並且如果更改可能會導致恐慌。

當不支援 AVX2 指令時,amd64 上的 SHA-1、SHA-256 和 SHA-512 現在速度較慢。自 2015 年以來生產的所有伺服器處理器(以及大多數其他處理器)都支援 AVX2。

crypto/ecdsa

新的 ParseRawPrivateKeyParseUncompressedPublicKeyPrivateKey.BytesPublicKey.Bytes 函式和方法實現了低階編碼,取代了使用 crypto/ellipticmath/big 函式和方法的需要。

啟用 FIPS 140-3 模式後,簽名速度現在快四倍,與非 FIPS 模式的效能相匹配。

crypto/ed25519

啟用 FIPS 140-3 模式後,簽名速度現在快四倍,與非 FIPS 模式的效能相匹配。

crypto/elliptic

已刪除某些 Curve 實現中隱藏且未文件化的 InverseCombinedMult 方法。

crypto/rsa

PublicKey 不再聲稱模數被視為秘密。VerifyPKCS1v15VerifyPSS 已經警告所有輸入都是公開的並且可能洩露,並且存在可以從其他公共值恢復模數的數學攻擊。

金鑰生成現在快三倍。

crypto/sha1

當 SHA-NI 指令可用時,amd64 上的雜湊速度現在快兩倍。

crypto/sha3

新的 SHA3.Clone 方法實現了 hash.Cloner

在 Apple M 處理器上,雜湊速度現在快兩倍。

crypto/tls

新的 ConnectionState.CurveID 欄位公開了用於建立連線的金鑰交換機制。

新的 Config.GetEncryptedClientHelloKeys 回撥可用於設定伺服器在客戶端傳送加密客戶端 Hello 擴充套件時使用的 EncryptedClientHelloKey

根據 RFC 9155,TLS 1.2 握手現在不允許 SHA-1 簽名演算法。它們可以透過 GODEBUG 設定 tlssha1=1 重新啟用。

當啟用 FIPS 140-3 模式時,TLS 1.2 中現在需要擴充套件主金鑰,並且現在允許 Ed25519 和 X25519MLKEM768。

TLS 伺服器現在優先選擇支援的最高協議版本,即使它不是客戶端最喜歡的協議版本。

TLS 客戶端和伺服器現在都更嚴格地遵循規範並拒絕不符合規範的行為。與相容對等方的連線應該不受影響。

crypto/x509

CreateCertificateCreateCertificateRequestCreateRevocationList 現在可以接受 crypto.MessageSigner 簽名介面以及 crypto.Signer。這允許這些函式使用實現“一次性”簽名介面的簽名器,其中雜湊作為簽名操作的一部分完成,而不是由呼叫方完成。

CreateCertificate 現在使用截斷的 SHA-256 來填充 SubjectKeyId(如果它缺失)。GODEBUG 設定 x509sha256skid=0 恢復為 SHA-1。

ParseCertificate 現在拒絕包含 BasicConstraints 擴充套件且包含負 pathLenConstraint 的證書。

ParseCertificate 現在更一致地處理使用 ASN.1 T61String 和 BMPString 型別編碼的字串。這可能會導致以前接受的一些格式錯誤的編碼現在被拒絕。

debug/elf

debug/elf 包添加了兩個新常量

go/ast

FilterPackagePackageExportsMergePackageFiles 函式,以及 MergeMode 型別及其常量,都已棄用,因為它們僅用於長期棄用的 ObjectPackage 機制。

新的 PreorderStack 函式,如 Inspect,遍歷語法樹並控制下降到子樹,但為了方便起見,它還在每個點提供包含節點的堆疊。

go/parser

ParseDir 函式已棄用。

go/token

新的 FileSet.AddExistingFiles 方法允許將現有的 File 新增到 FileSet,或者為任意一組 File 構造 FileSet,從而緩解了長期執行的應用程式中單個全域性 FileSet 相關的問題。

go/types

Var 現在有一個 Var.Kind 方法,它將變數分類為:包級、接收器、引數、結果、區域性變數或結構欄位。

新的 LookupSelection 函式查詢給定名稱和接收器型別的欄位或方法,就像現有的 LookupFieldOrMethod 函式一樣,但以 Selection 的形式返回結果。

雜湊

新的 XOF 介面可以由“可擴充套件輸出函式”實現,這些函式是具有任意或無限輸出長度的雜湊函式,例如 SHAKE

實現新 Cloner 介面的雜湊可以返回其狀態的副本。所有標準庫 Hash 實現現在都實現了 Cloner

hash/maphash

新的 Hash.Clone 方法實現了 hash.Cloner

io/fs

新的 ReadLinkFS 介面提供了在檔案系統中讀取符號連結的能力。

日誌/slog

GroupAttrsAttr 值切片建立組 Attr

Record 現在有一個 Source 方法,返回其源位置或 nil(如果不可用)。

mime/multipart

新的輔助函式 FileContentDisposition 構建多部分 Content-Disposition 標頭欄位。

net

LookupMXResolver.LookupMX 現在返回看起來像有效 IP 地址的 DNS 名稱,以及有效的域名。以前,如果名稱伺服器返回 IP 地址作為 DNS 名稱,LookupMX 會根據 RFC 的要求將其丟棄。然而,實際上名稱伺服器有時會返回 IP 地址。

在 Windows 上,ListenMulticastUDP 現在支援 IPv6 地址。

在 Windows 上,現在可以在 os.File 和網路連線之間進行轉換。具體來說,現在實現了 FileConnFilePacketConnFileListener 函式,並返回與開啟的檔案對應的網路連線或監聽器。同樣,現在實現了 TCPConnUDPConnUnixConnIPConnTCPListenerUnixListenerFile 方法,並返回網路連線的底層 os.File

net/http

新的 CrossOriginProtection 透過拒絕不安全的跨域瀏覽器請求來實現對 跨站請求偽造 (CSRF) 的保護。它使用 現代瀏覽器 Fetch 元資料,不需要令牌或 Cookie,並支援基於來源和基於模式的繞過。

os

在 Windows 上,NewFile 現在支援為非同步 I/O 開啟的控制代碼(即在 syscall.CreateFile 呼叫中指定了 syscall.FILE_FLAG_OVERLAPPED)。這些控制代碼與 Go 執行時的 I/O 完成埠關聯,這為生成的 File 提供了以下好處

此增強功能對於透過 Windows 上的命名管道進行通訊的應用程式特別有益。

請注意,控制代碼一次只能與一個完成埠關聯。如果提供給 NewFile 的控制代碼已與完成埠關聯,則返回的 File 將降級為同步 I/O 模式。在這種情況下,I/O 方法將阻塞作業系統執行緒,並且截止日期方法無效。

DirFSRoot.FS 返回的檔案系統實現了新的 io/fs.ReadLinkFS 介面。CopyFS 在複製實現 io/fs.ReadLinkFS 的檔案系統時支援符號連結。

Root 型別支援以下附加方法

reflect

新的 TypeAssert 函式允許將 Value 直接轉換為給定型別的 Go 值。這類似於對 Value.Interface 的結果使用型別斷言,但避免了不必要的記憶體分配。

regexp/syntax

\p{name}\P{name} 字元類語法現在接受 Any、ASCII、Assigned、Cn 和 LC 名稱,以及像 \pL 這樣的 Unicode 類別別名 \p{Letter}。根據 Unicode TR18,它們現在也使用不區分大小寫的名稱查詢,忽略空格、下劃線和連字元。

runtime

AddCleanup 安排的清理函式現在併發並行執行,使得清理對於像 unique 包這樣的繁重使用更可行。請注意,如果單個清理必須長時間執行或阻塞以避免阻塞清理佇列,它們仍應將其工作分流到新的 goroutine。

一個新的 GODEBUG=checkfinalizers=1 設定有助於查詢 finalizer 和 cleanup 的常見問題,例如 GC 指南中描述的問題。在此模式下,執行時在每個垃圾收集週期執行診斷,並將定期向 stderr 報告 finalizer 和 cleanup 佇列長度,以幫助識別長時間執行的 finalizer 和/或 cleanup 的問題。有關更多詳細資訊,請參閱 GODEBUG 文件

新的 SetDefaultGOMAXPROCS 函式將 GOMAXPROCS 設定為執行時預設值,就好像未設定 GOMAXPROCS 環境變數一樣。這對於啟用新的 GOMAXPROCS 預設值很有用,如果它已被 GOMAXPROCS 環境變數或先前對 GOMAXPROCS 的呼叫停用。

runtime/pprof

執行時內部鎖爭用的互斥鎖配置檔案現在正確指向導致延遲的關鍵部分的末尾。這與配置檔案對於 sync.Mutex 值爭用的行為相匹配。GODEBUGruntimecontentionstacks 設定(允許選擇 Go 1.22 到 1.24 在此配置檔案部分的異常行為)現在已刪除。

sync

新的 WaitGroup.Go 方法使得建立和計數 goroutine 的常見模式更加方便。

testing

新的方法 T.AttrB.AttrF.Attr 向測試日誌發出屬性。屬性是與測試關聯的任意鍵和值。

例如,在名為 TestF 的測試中,t.Attr("key", "value") 發出

=== ATTR  TestF key value

使用 -json 標誌,屬性顯示為新的“attr”操作。

TBF 的新 Output 方法提供了一個 io.Writer,它寫入與 TB.Log 相同的測試輸出流。與 TB.Log 一樣,輸出是縮排的,但不包括檔案和行號。

如果並行測試正在執行,AllocsPerRun 函式現在會發生恐慌。AllocsPerRun 的結果在其他測試執行時本質上是不穩定的。新的恐慌行為有助於捕獲此類錯誤。

testing/fstest

MapFS 實現了新的 io/fs.ReadLinkFS 介面。TestFS 將驗證 io/fs.ReadLinkFS 介面的功能(如果已實現)。TestFS 將不再跟蹤符號連結以避免無界遞迴。

unicode

新的 CategoryAliases 對映提供對類別別名名稱的訪問,例如“Letter”表示“L”。

新的類別 CnLC 分別定義了未分配的碼點和帶大小寫的字母。這些始終由 Unicode 定義,但在 Go 的早期版本中無意中省略了。C 類別現在包含 Cn,這意味著它添加了所有未分配的碼點。

獨特

unique 包現在更積極、更高效地並行回收內部化值。因此,使用 Make 的應用程式在內部化大量真正唯一值時,記憶體膨脹的可能性更小。

傳遞給 Make 的包含 Handle 的值以前需要多個垃圾收集週期才能收集,與 Handle 值鏈的深度成比例。現在,一旦未使用,它們會在單個週期內迅速收集。

移植

Darwin

正如 Go 1.24 發行說明中宣佈的那樣,Go 1.25 需要 macOS 12 Monterey 或更高版本。對以前版本的支援已停止。

Windows

Go 1.25 是最後一個包含損壞的 32 位 windows/arm 埠(GOOS=windows GOARCH=arm)的版本。它將在 Go 1.26 中刪除。

龍芯64

linux/loong64 埠現在支援競態檢測器,使用 runtime.SetCgoTraceback 從 C 程式碼收集回溯資訊,並使用內部連結模式連結 cgo 程式。

RISC-V

linux/riscv64 埠現在支援 plugin 構建模式。

GORISCV64 環境變數現在接受一個新值 rva23u64,它選擇 RVA23U64 使用者模式應用程式配置檔案。