Go 1.23 釋出說明

Go 1.23 簡介

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

語言變化

“for-range” 迴圈中的 “range” 子句現在接受以下型別的迭代器函式

func(func() bool)
func(func(K) bool)
func(func(K, V) bool)

作為 range 表示式。迭代器引數函式的呼叫會生成 “for-range” 迴圈的迭代值。有關詳細資訊,請參閱 iter 包文件、語言規範“函式型別上的 Range” 部落格文章。有關動機,請參閱 2022 年的“range-over-func” 討論

Go 1.23 包括對泛型類型別名的預覽支援。使用 GOEXPERIMENT=aliastypeparams 構建工具鏈可在包內啟用此功能。(目前尚不支援跨包邊界使用泛型別名型別。)

工具

遙測

從 Go 1.23 開始,Go 工具鏈可以收集使用情況和故障統計資訊,幫助 Go 團隊瞭解 Go 工具鏈的使用方式及其執行情況。我們將這些統計資訊稱為Go 遙測

Go 遙測是一個選擇加入系統,由go telemetry 命令控制。預設情況下,工具鏈程式會將統計資訊收集到計數器檔案中,這些檔案可以在本地檢查,但否則不會使用(go telemetry local)。

為了幫助我們保持 Go 的良好執行並瞭解 Go 的使用情況,請考慮執行 go telemetry on 來選擇加入 Go 遙測。在此模式下,匿名計數器報告將每週上傳到 telemetry.go.dev,在那裡它們將被彙總成圖表,並提供給任何想要分析資料的 Go 貢獻者或使用者下載。有關 Go 遙測系統的更多詳細資訊,請參閱“Go 遙測”。

Go 命令

設定 GOROOT_FINAL 環境變數不再有任何作用(#62047)。將 go 命令安裝到 $GOROOT/bin/go 以外位置的發行版應安裝符號連結,而不是重新定位或複製 go 二進位制檔案。

新的 go env -changed 標誌會導致命令僅列印其有效值與在空環境中未事先使用 -w 標誌獲得的預設值不同的設定。

新的 go mod tidy -diff 標誌會導致命令不修改檔案,而是將必要的更改列印為統一的 diff。如果需要更新,它將以非零程式碼退出。

go list -m -json 命令現在包含新的 SumGoModSum 欄位。這與 go mod download -json 命令的現有行為類似。

go.modgo.work 中的新 godebug 指令聲明瞭一個適用於所用工作模組或工作區的 GODEBUG 設定

Vet

go vet 子命令現在包括 stdversion 分析器,該分析器標記引用檔案中生效的 Go 版本過舊的符號。(有效版本由檔案封閉 go.mod 檔案中的 go 指令以及檔案中的任何 //go:build 約束決定。)

例如,它將報告一個模組檔案中對 reflect.TypeFor 函式(在 go1.22 中引入)的引用診斷,該模組的 go.mod 檔案指定 go 1.21

Cgo

cmd/cgo 支援新的 -ldflags 標誌,用於將標誌傳遞給 C 連結器。go 命令會自動使用它,避免在 CGO_LDFLAGS 非常大時出現“引數列表過長”錯誤。

Trace

trace 工具現在能更好地容忍部分損壞的跟蹤,它會嘗試恢復可以恢復的跟蹤資料。此功能在檢視程式崩潰期間收集的跟蹤時特別有用,因為在大多數情況下,導致崩潰的跟蹤資料現在將可恢復

執行時

執行時在未處理的 panic 或其他致命錯誤後列印的跟蹤現在將錯誤訊息的第二行和後續行(例如,panic 的引數)縮排一個製表符,以便可以將其與第一個 goroutine 的堆疊跟蹤明確區分開來。有關討論,請參閱 #64590

編譯器

使用配置檔案引導最佳化進行構建的構建時間開銷已顯著降低。以前,大型構建在啟用 PGO 後可能會導致構建時間增加 100% 以上。在 Go 1.23 中,開銷應為個位數百分比。

Go 1.23 中的編譯器現在可以重疊函式中不相交區域中訪問的區域性變數的堆疊幀槽,從而減少 Go 應用程式的堆疊使用。

對於 386 和 amd64,編譯器將使用 PGO 中的資訊來對齊迴圈中某些熱塊。這會額外將效能提高 1-1.5%,但會增加 0.1% 的文字和二進位制大小。目前這僅在 386 和 amd64 上實現,因為它在其他平臺上沒有顯示出改進。可以使用 -gcflags=[=-d=alignhot=0 停用熱塊對齊。

連結器

連結器現在禁止使用 //go:linkname 指令引用標準庫(包括執行時)中未在其定義上標記為 //go:linkname 的內部符號。同樣,連結器禁止彙編程式碼引用此類符號。為了向後相容,在大型開原始碼庫中發現的現有 //go:linkname 用法仍然受支援。任何對標準庫內部符號的新引用都將被禁止。

連結器命令列標誌 -checklinkname=0 可用於停用此檢查,用於除錯和實驗目的。

構建動態連結的 ELF 二進位制檔案(包括 PIE 二進位制檔案)時,新的 -bindnow 標誌啟用即時函式繫結。

標準庫

計時器更改

Go 1.23 對 time.Timertime.Ticker 的實現進行了兩項重大更改。

首先,不再被程式引用的 TimerTicker 會立即符合垃圾回收條件,即使它們的 Stop 方法尚未被呼叫。早期版本的 Go 不會在未停止的 Timer 觸發之前收集它們,並且從不收集未停止的 Ticker

其次,與 TimerTicker 關聯的計時器通道現在是無緩衝的,容量為 0。此更改的主要影響是 Go 現在保證對於對 ResetStop 方法的任何呼叫,在該呼叫之前準備的任何陳舊值都不會在該呼叫之後傳送或接收。早期版本的 Go 使用帶有一個元素緩衝區的通道,這使得正確使用 ResetStop 變得困難。此更改的一個可見效果是計時器通道的 lencap 現在返回 0 而不是 1,這可能會影響輪詢長度以決定計時器通道上的接收是否成功的程式。此類程式碼應使用非阻塞接收。

這些新行為僅在主 Go 程式位於其 go.mod go 行使用 Go 1.23.0 或更高版本的模組中時才啟用。當 Go 1.23 構建舊程式時,舊行為仍然有效。新的 GODEBUG 設定 asynctimerchan=1 可用於即使程式在其 go.mod 檔案中指定 Go 1.23.0 或更高版本時,也恢復為非同步通道行為。

新的 unique 包

新的 unique 包提供了規範化值(例如“內部化”或“雜湊一致”)的功能。

任何可比較型別的值都可以透過新的 Make[T] 函式進行規範化,該函式以 Handle[T] 的形式生成對值的規範副本的引用。當且僅當用於生成控制代碼的值相等時,兩個 Handle[T] 才相等,從而允許程式去重值並減少其記憶體佔用。比較兩個 Handle[T] 值是高效的,可以簡化為簡單的指標比較。

迭代器

新的 iter 包提供了用於處理使用者定義迭代器的基本定義。

slices 包添加了幾個與迭代器一起使用的函式

  • All 返回切片索引和值的迭代器。
  • Values 返回切片元素的迭代器。
  • Backward 返回一個反向迴圈切片的迭代器。
  • Collect 從迭代器中收集值到一個新切片中。
  • AppendSeq 將迭代器中的值附加到現有切片。
  • Sorted 從迭代器中收集值到一個新切片中,然後對切片進行排序。
  • SortedFunc 類似於 Sorted 但帶有比較函式。
  • SortedStableFunc 類似於 SortFunc 但使用穩定排序演算法。
  • Chunk 返回切片中最多 n 個元素的連續子切片的迭代器。

maps 包添加了幾個與迭代器一起使用的函式

  • All 返回對映中的鍵值對的迭代器。
  • Keys 返回對映中鍵的迭代器。
  • Values 返回對映中值的迭代器。
  • Insert 將迭代器中的鍵值對新增到現有對映。
  • Collect 從迭代器中收集鍵值對到一個新對映中並返回它。

新的 structs 包

新的 structs 包提供了用於結構體欄位的型別,這些欄位修改了包含結構體型別的屬性,例如記憶體佈局。

在此版本中,唯一此類型別是 HostLayout,它指示具有該型別欄位的結構體具有符合主機平臺期望的佈局。HostLayout 應該用於傳遞給、從主機 API 返回或透過指向主機 API 的指標訪問的型別。如果沒有此標記,語言規範不保證結構體佈局順序,儘管自 Go 1.23 起,主機和語言佈局恰好匹配。

對庫的微小更改

archive/tar

如果傳遞給 FileInfoHeader 的引數實現了新的 FileInfoNames 介面,則將使用介面方法設定檔案頭的 Uname/Gname。這允許應用程式覆蓋系統相關的 Uname/Gname 查詢。

crypto/tls

TLS 客戶端現在支援加密客戶端 Hello 草案規範。可以透過將 Config.EncryptedClientHelloConfigList 欄位設定為要連線到的主機的編碼 ECHConfigList 來啟用此功能。

QUIC 實現使用的 QUICConn 型別包括報告會話恢復狀態的新事件,並提供了一種 QUIC 層將資料新增到會話票證和會話快取條目的方法。

Config.CipherSuites 為 nil 時,3DES 密碼套件已從預設列表中刪除。可以透過將 tls3des=1 新增到 GODEBUG 環境變數來恢復預設設定。

Config.CurvePreferences 為 nil 時,實驗性的後量子金鑰交換機制 X25519Kyber768Draft00 現在預設啟用。可以透過將 tlskyber=0 新增到 GODEBUG 環境變數來恢復預設設定。這在處理無法正確處理大記錄的錯誤 TLS 伺服器時可能很有用,導致握手期間超時(請參閱 TLS 後量子 TL;DR 失敗)。

Go 1.23 更改了 X509KeyPairLoadX509KeyPair 的行為,以填充返回的 CertificateCertificate.Leaf 欄位。為此行為添加了新的 x509keypairleaf GODEBUG 設定

crypto/x509

CreateCertificateRequest 現在正確支援 RSA-PSS 簽名演算法。

CreateCertificateRequestCreateRevocationList 現在使用簽名者的公鑰驗證生成的簽名。如果簽名無效,則返回錯誤。自 Go 1.16 以來,這一直是 CreateCertificate 的行為。

x509sha1 GODEBUG 設定將在下一個 Go 主要版本(Go 1.24)中刪除。這意味著 crypto/x509 將不再支援驗證使用基於 SHA-1 的簽名演算法的證書上的簽名。

新的 ParseOID 函式解析點編碼的 ASN.1 物件識別符號字串。OID 型別現在實現了 encoding.BinaryMarshalerencoding.BinaryUnmarshalerencoding.TextMarshalerencoding.TextUnmarshaler 介面。

database/sql

現在,由 driver.Valuer 實現返回的錯誤被包裝起來,以便在 DB.QueryDB.ExecDB.QueryRow 等操作期間改進錯誤處理。

debug/elf

debug/elf 包現在定義了 PT_OPENBSD_NOBTCFI。此 ProgType 用於在 OpenBSD 二進位制檔案上停用分支跟蹤控制流完整性 (BTCFI) 強制執行。

現在定義了符號型別常量 STT_RELCSTT_SRELCSTT_GNU_IFUNC

encoding/binary

新的 EncodeDecode 函式是 ReadWrite 的位元組切片等效項。Append 允許將多個數據封送(marshal)到同一個位元組切片中。

go/ast

新的 Preorder 函式返回一個方便的迭代器,遍歷語法樹的所有節點。

go/types

Func 型別表示函式或方法符號,現在有一個 Func.Signature 方法,該方法返回函式的型別,該型別始終是 Signature

Alias 型別現在有一個 Rhs 方法,該方法返回其宣告右側的型別:給定 type A = B,A 的 Rhs 是 B。(#66559

已新增方法 Alias.OriginAlias.SetTypeParamsAlias.TypeParamsAlias.TypeArgs。它們是泛型別名型別所需的。

預設情況下,go/types 現在為類型別名生成 Alias 型別節點。此行為可以透過 GODEBUG gotypesalias 標誌控制。其預設值已從 Go 1.22 中的 0 更改為 Go 1.23 中的 1。

math/rand/v2

已新增 Uint 函式和 Rand.Uint 方法。它們在 Go 1.22 中被無意中遺漏了。

新的 ChaCha8.Read 方法實現了 io.Reader 介面。

net

新的型別 KeepAliveConfig 允許透過新的 TCPConn.SetKeepAliveConfig 方法以及 DialerListenConfig 的新 KeepAliveConfig 欄位,對 TCP 連線的保活選項進行微調。

DNSError 型別現在包裝由超時或取消引起的錯誤。例如,errors.Is(someDNSErr, context.DeadlineExceeded) 現在將報告 DNS 錯誤是否由超時引起。

新的 GODEBUG 設定 netedns0=0 停用在 DNS 請求上傳送 EDNS0 附加頭,因為據報道它們會破壞某些調變解調器上的 DNS 伺服器。

net/http

Cookie 現在保留 cookie 值周圍的雙引號。新的 Cookie.Quoted 欄位指示 Cookie.Value 最初是否被引用。

新的 Request.CookiesNamed 方法檢索所有與給定名稱匹配的 cookie。

新的 Cookie.Partitioned 欄位標識具有 Partitioned 屬性的 cookie。

ServeMux 使用的模式現在允許方法名後有一個或多個空格或製表符。以前只允許一個空格。

新的 ParseCookie 函式解析 Cookie 頭部值並返回其中設定的所有 cookie。由於相同的 cookie 名稱可以出現多次,因此返回的 Values 可以包含給定鍵的多個值。

新的 ParseSetCookie 函式解析 Set-Cookie 頭部值並返回一個 cookie。如果存在語法錯誤,則返回錯誤。

ServeContentServeFileServeFileFS 在提供錯誤時現在會移除 Cache-ControlContent-EncodingEtagLast-Modified 頭部。這些頭部通常適用於非錯誤內容,而不適用於錯誤文字。

包裝 ResponseWriter 並應用即時編碼(例如 Content-Encoding: gzip)的中介軟體在此更改後將無法工作。ServeContentServeFileServeContent 處理 Range 請求時,改變所服務內容大小(例如透過壓縮)的中介軟體已經無法正常工作。即時壓縮應使用 Transfer-Encoding 頭部而不是 Content-Encoding

對於入站請求,新的 Request.Pattern 欄位包含與請求匹配的 ServeMux 模式(如果有)。當設定 GODEBUG=httpmuxgo121=1 時,此欄位未設定。

net/http/httptest

新的 NewRequestWithContext 方法使用 context.Context 建立一個傳入請求。

net/netip

在 Go 1.22 及更早版本中,使用 reflect.DeepEqual 比較包含 IPv4 地址的 Addr 與包含該地址的 IPv4 對映 IPv6 形式的 Addr.Compare 比較時不同。此錯誤現已修復,所有三種方法現在都報告相同的結果。

os

Stat 函式現在為 Windows 上作為 Unix 套接字的檔案設定 ModeSocket 位。這些檔案透過其重新解析標籤設定為 IO_REPARSE_TAG_AF_UNIX 來標識。

在 Windows 上,LstatStat 報告的重新解析點的模式位發生了變化。掛載點不再設定 ModeSymlink,並且不是符號連結、Unix 套接字或去重檔案的重新解析點現在始終設定 ModeIrregular。此行為由 winsymlink 設定控制。對於 Go 1.23,它預設為 winsymlink=1。以前的版本預設為 winsymlink=0

CopyFS 函式將 io/fs.FS 複製到本地檔案系統。

在 Windows 上,Readlink 不再嘗試將卷規範化為驅動器號,這並非總是可能的。此行為由 winreadlinkvolume 設定控制。對於 Go 1.23,它預設為 winreadlinkvolume=1。以前的版本預設為 winreadlinkvolume=0

在支援 pidfd 的 Linux 上(通常是 Linux v5.4+),Process 相關函式和方法內部使用 pidfd(而不是 PID),消除了當作業系統重用 PID 時可能發生的錯誤定位。Pidfd 支援對使用者完全透明,除了程序可能擁有的額外程序檔案描述符。

path/filepath

新的 Localize 函式安全地將斜槓分隔的路徑轉換為作業系統路徑。

在 Windows 上,EvalSymlinks 不再評估掛載點,這是許多不一致和錯誤的來源。此行為由 winsymlink 設定控制。對於 Go 1.23,它預設為 winsymlink=1。以前的版本預設為 winsymlink=0

在 Windows 上,EvalSymlinks 不再嘗試將卷規範化為驅動器號,這並非總是可能的。此行為由 winreadlinkvolume 設定控制。對於 Go 1.23,它預設為 winreadlinkvolume=1。以前的版本預設為 winreadlinkvolume=0

reflect

Value 中同名方法同義的新方法已新增到 Type

  1. Type.OverflowComplex
  2. Type.OverflowFloat
  3. Type.OverflowInt
  4. Type.OverflowUint

新的 SliceAt 函式類似於 NewAt,但用於切片。

Value.PointerValue.UnsafePointer 方法現在支援 String 型別的 值。

新的方法 Value.SeqValue.Seq2 返回序列,這些序列遍歷值,就像它在 for/range 迴圈中使用一樣。新的方法 Type.CanSeqType.CanSeq2 分別報告呼叫 Value.SeqValue.Seq2 是否會在不 panic 的情況下成功。

runtime/debug

SetCrashOutput 函式允許使用者指定一個備用檔案,執行時應將其致命崩潰報告寫入該檔案。它可用於為所有意外崩潰構建自動化報告機制,而不僅僅是那些明確使用 recover 的 goroutine 中的崩潰。

runtime/pprof

allocmutexblockthreadcreategoroutine 配置檔案的最大堆疊深度已從 32 幀提高到 128 幀。

runtime/trace

當程式因未捕獲的 panic 而崩潰時,執行時現在會顯式重新整理跟蹤資料。這意味著,如果在跟蹤活動期間程式崩潰,跟蹤中將提供更完整的跟蹤資料。

slices

Repeat 函式返回一個新切片,該切片重複提供的切片給定次數。

sync

Map.Clear 方法刪除所有條目,導致 Map 為空。它類似於 clear

sync/atomic

新的 AndOr 運算子對給定輸入應用按位 ANDOR,並返回舊值。

syscall

syscall 包現在在 Windows 上定義了 WSAENOPROTOOPT

GetsockoptInt 函式現在在 Windows 上受支援。

testing/fstest

TestFS 現在返回一個結構化錯誤,該錯誤可以解包(透過方法 Unwrap() []error)。這允許使用 errors.Iserrors.As 檢查錯誤。

text/template

模板現在支援新的“else with”操作,這在某些用例中可以降低模板複雜性。

time

ParseParseInLocation 現在會在時區偏移超出範圍時返回錯誤。

在 Windows 上,TimerTicker 以及使 goroutine 休眠的函式(例如 Sleep)的時間解析度已從 15.6ms 提高到 0.5ms。

unicode/utf16

RuneLen 函式返回 rune 的 UTF-16 編碼中的 16 位字數。如果 rune 不是有效的 UTF-16 編碼值,則返回 -1。

移植

Darwin

正如 Go 1.22 釋出說明中宣佈的那樣,Go 1.23 要求 macOS 11 Big Sur 或更高版本;對以前版本的支援已停止。

Linux

Go 1.23 是最後一個需要 Linux 核心版本 2.6.32 或更高版本的版本。Go 1.24 將需要 Linux 核心版本 3.2 或更高版本。

OpenBSD

Go 1.23 添加了對 64 位 RISC-V 上的 OpenBSD 的實驗性支援(GOOS=openbsd, GOARCH=riscv64)。

ARM64

Go 1.23 引入了新的 GOARM64 環境變數,該變數在編譯時指定 ARM64 架構的最低目標版本。允許的值為 v8.{0-9}v9.{0-5}。這後面可以跟一個指定目標硬體實現的擴充套件的選項。有效選項為 ,lse,crypto

GOARM64 環境變數預設為 v8.0

RISC-V

Go 1.23 引入了一個新的 GORISCV64 環境變數,用於選擇要編譯的 RISC-V 使用者模式應用程式配置檔案。允許的值為 rva20u64rva22u64

GORISCV64 環境變數預設為 rva20u64

Wasm

GOROOT/misc/wasm 中的 go_wasip1_wasm_exec 指令碼已停止支援 wasmtime < 14.0.0 的版本。