Go 1.23 發行說明

Go 1.23 簡介

Go 1.22 推出六個月後,Go 的最新版本 1.23 誕生。其大部分的變更皆在工具鏈、執行時期和函式庫的實作中。一如往常,此版本承諾維持 Go 1 的 相容性。我們盼望幾乎所有 Go 程式都能像之前一樣持續編譯並執行。

語言的變更

現在,「for-range」迴圈中的「範圍」子句接受以下類型的反覆器函式

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

作為範圍運算式。呼叫反覆器引數函式會產生「for-range」迴圈的迭代值。如需詳細資訊,請參閱 iter 套件文件、語言規格 以及 迭代函式類型部落格文章。如需瞭解動機,請參閱 2022 年的 「函式範圍」討論

Go 1.23 包含對 一般類型別名 的預覽支援。使用 GOEXPERIMENT=aliastypeparams 建置工具鏈可在套件中啟用此功能。(跨套件邊界使用一般別名類型尚未獲得支援。)

工具

遠距測量

Go 1.23 起,Go 工具鏈可收集使用狀況和中斷統計資料,協助 Go 團隊了解 Go 工具鏈的使用方式以及運作狀況。我們將這些統計資料稱為 Go 遠距測量

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

為了讓我們能持續讓 Go 順利運作良好,並了解 Go 的使用情況,請考慮加入 Go 遠程量測,方法是執行 go telemetry on。在這種模式下,匿名的計數器報告會每週上傳至telemetry.go.dev,並彙總成圖表,供任何想要分析資料的 Go 貢獻者或使用者下載。詳情請參閱「Go 遠程量測」。

Go 指令

設定 GOROOT_FINAL 環境變數不再會產生任何影響 (#62047)。將 go 指令安裝到 $GOROOT/bin/go 以外位置的發行版,應安裝符號連接,而非重新定位或複製 go 二進位檔。

新的 go env -changed 參數會造成指令僅列印其有效值與在沒有先前使用 -w 參數的空環境中取得的預設值不同的設定。

新的 go mod tidy -diff 參數會造成指令不修改檔案,而是以統一差異化 (unified 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 約束來決定。)

舉例來說,如果檔案中的 go.mod 檔案指定 go 1.21,則它會為一個對 reflect.TypeFor 函數 (於 go1.22 中新增) 的參考回報一個診斷資料。

Cgo

cmd/cgo 支援新的 -ldflags 參數,用於傳遞參數至 C 連結器。go 指令會自動使用它,如此一來可避免使用非常大的 CGO_LDFLAGS 時出現「引數清單過長」的錯誤。

追蹤

trace 工具現在能更好地耐受部分損壞的追蹤,它會嘗試還原所有能還原的追蹤資料。當檢視在程式當機時收集的追蹤時,此功能特別有用,因為在大部分情況下,都會 可復原 當機前的追蹤資料。

執行時間

執行時間在未處理的恐慌或其他致命錯誤後列印的追蹤回溯,現在會將錯誤訊息的第二行與後續行(例如,恐慌引數)以單個 TAB 縮排,以便與第一個 goroutine 的堆疊追蹤清楚區分。詳見 #64590 的討論。

編譯器

配合 Profil Guided Optimization 建置的建置時間開銷已大幅縮減,過去在開啟 PGO 時,大型建置可能會導致建置時間增加 100% 以上。在 Go 1.23 中,開銷會控制在個位數百分比。

Go 1.23 中的編譯器現在可以在函式的不同區段中存取局部變數的堆疊架構插槽,這減少了 Go 應用程式的堆疊使用量。

對於 386 和 amd64,編譯器會使用 PGO 的資訊,在迴圈中對齊特定的熱區塊,並以額外 0.1% 的文字和二進位大小,來改善 1-1.5% 的效能。目前僅在 386 和 amd64 上實現此功能,因為在其他平台上尚未顯示改善。熱區塊對齊可以用 -gcflags=[<packages>=]-d=alignhot=0 來停用。

連結器

連結器現在不允許使用一個 //go:linkname 指令來參照標準函式庫中(包括執行時間)未標示有 //go:linkname 的內部符號定義。同樣地,連結器也不允許組譯程式碼參照此類符號。為了向後相容性,從大型開放原始碼程式碼集中發現的現有 //go:linkname 用法仍會支援,禁止任何對標準函式庫內部符號的新參照。

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

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

標準函式庫

計時器變更

Go 1.23 對 time.Timertime.Ticker 的實作進行兩項重大的變更。

首先,程式不再參照的 `Timer` 與 `Ticker`,會立即符合垃圾回收的資格,即使其 `Stop` 方法尚未呼叫。較早版本的 Go 只有在觸發後才會收集未停止的 `Timer`,而且從未收集未停止的 `Ticker`。

其次,與 `Timer` 或 `Ticker` 相關聯的計時器頻道現在是非快取的,容量為 0。變更的目的是,現在 Go 能夠保證:對於對 `Reset` 或 `Stop` 方法的任何呼叫,在呼叫之後,任何在這之前準備的過期值都不會被傳送或接收。較早版本的 Go 使用具備一個元素快取的頻道,使得難以正確使用 `Reset` 和 `Stop`。這個變更的可見影響是:計時器頻道的 `len` 與 `cap` 現在會傳回 0,而不是 1,這可能會影響透過輪詢長度來決定計時器頻道上的接收是否會成功的程式。此類程式碼應改用非阻斷式接收。

這些新行為僅在編寫主 Go 程式時,在包含 `go.mod` `go` 行的模組中啟用,且 Go 的版本為 1.23.0 或以上。當 Go 1.23 編譯舊程式時,舊行為仍舊有效。新的 GODEBUG 設定 asynctimerchan=1 可用於回復到非同步頻道行為,即使程式在 `go.mod` 檔案中命名 Go 1.23.0 或較新版本。

新的獨特套件

新的 unique 套件提供正則化值的工具 (例如「內部化」或「雜湊協定」)。

可以將任何可比較類型的值正則化,使用新的 `Make[T]` 函式。此函式會產生一個正則化值副本的參考,形式為 `Handle[T]`。兩個 `Handle[T]` 相等,若且唯若用於產生這些處理器的值相等,允許程式去重製值及減少其記憶體佔用量。比較兩個 `Handle[T]` 值很有效率,會簡化到簡單的指標比較。

反覆運算器

新的 iter 套件提供使用自訂反覆運算器的基本定義。

slices 套件新增數個與反覆運算器搭配使用的函式

maps 套件新增數個函式,用於搭配反覆器執行各種動作

新的 structs 套件

新的 structs 套件提供了結構欄位的類型,該欄位可修改其包含結構類型中的欄位,例如記憶體配置。

在此版本中,唯一此類型的欄位為 HostLayout,表示含有該欄位的結構具有符合主機平台預期的配置。HostLayout 應在傳遞給主機 API、從主機 API 傳回資料、或透過傳遞到/從主機 API 的指標存取的類型中使用。如果不使用此標記,雖然在 Go 1.23 中主機與語言配置會碰巧相符,但結構配置順序不會受到語言規格保證。

函式庫的次要變更

archive/tar

如果傳遞給 FileInfoHeader 的引數實作新的 FileInfoNames 介面,則將會使用介面方法來設定檔案標頭的 Uname/Gname。這可讓應用程式覆寫依賴系統的 Uname/Gname 查詢機制。

crypto/tls

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

QUICConn 型別是 QUIC 實作所使用,包含與會話恢復狀態相關的事件的新報告,並提供 QUIC 層級將資料新增至會話票證與會話快取項目的方式。

3DES 加密組已從在 Config.CipherSuites 為 nil 時使用的預設清單中刪除。可在 GODEBUG 環境變數中新增 tls3des=1,以回復預設值。

Config.CurvePreferences 為 nil 時,現在會預設啟用實驗性量子密碼交換機制 X25519Kyber768Draft00。可以藉由將 tlskyber=0 加入 GODEBUG 環境變數來回復預設設定。

Go 1.23 變更了 X509KeyPairLoadX509KeyPair 的行為,讓它們會填充傳回 CertificateCertificate.Leaf 欄位。為了這個行為,加入了新的 x509keypairleaf GODEBUG 設定

crypto/x509

CreateCertificateRequest 現在正確地支援了 RSA-PSS 簽章演算法。

CreateCertificateRequestCreateRevocationList 現在會使用簽署者的公開金鑰驗證所產生的簽章。如果簽章無效,會傳回錯誤。自從 Go 1.16 以來,CreateCertificate 已經有了這個行為。

在下一版 Go 大版本 (Go 1.24) 中會移除 x509sha1 GODEBUG 設定。這表示 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 函式是位元組切片等效於 ReadWriteAppend 可以將多個資料封裝到同一個位元組切片中。

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 類型允許微調 TCP 連線的 Keep-Alive 選項,透過新的 TCPConn.SetKeepAliveConfig 方法,以及 DialerListenConfig 的新 KeepAliveConfig 欄位。

DNSError 類型現在會包裝因逾時或取消所造成的錯誤。例如,errors.Is(someDNSErr, context.DeadlineExceedeed) 現在會回報 DNS 錯誤是否因逾時所導致。

新的 GODEBUG 設定 netedns0=0 會停用在 DNS 要求中傳送 EDNS0 額外標頭,因為據報這些標頭會在某些數據機上中斷 DNS 伺服器。

net/http

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

新的 Request.CookiesNamed 方法會擷取所有與既定名稱相符的 Cookie。

新的 Cookie.Partitioned 欄位識別具有分區屬性的 cookie。

ServeMux 使用的模式現在允許方法名稱後有一個或多個空格或標籤。之前,只允許一個空格。

新的 ParseCookie 函數會剖析 Cookie 標頭值並傳回設定在其中的所有 Cookie。由於相同的 Cookie 名稱可能出現多次,所以傳回的 Values 可為特定金鑰包含多個值。

新的 ParseSetCookie 函數會剖析 Set-Cookie 標頭值並傳回 Cookie。它會在語法錯誤時傳回錯誤。

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

包裝 ResponseWriter 並套用即時編碼的中介軟體 (例如 Content-Encoding: gzip) 在此變更後將無法運作。ServeContentServeFileServeFileFS 的先前行為可能透過設定 GODEBUG=httpservecontentkeepheaders=1 來回復。

請注意,會變更所提供內容大小的中介軟體 (例如透過壓縮) 當 ServeContent 處理 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 時,會不正確地傳回 true,即使使用 ==Addr.Compare 來比較時,這些 Addr 值是不同的。現在已修正此錯誤,而三種方式現在都會報告相同的結果。

os

Stat 函數現在會為 Windows 上的 Unix Socket 設定 ModeSocket 位元組。這些檔案會透過設定為 IO_REPARSE_TAG_AF_UNIX 的重新解析標籤來識別。

在 Windows 系統中,LstatStat 回報的重新分派的點的模式位元有所更改。掛載點不再有 ModeSymlink 設定,而重新分派的點(並非符號連結、Unix socket 或重複資料刪除檔案)現在始終設有 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 是否會成功,而不會發生恐慌。

runtime/debug

SetCrashOutput 函數現在允許使用者指定替代檔案,讓執行時期寫入其致命故障報告。現在我們可以使用它建立所有意外故障的自動報告機制,而不再只限在明確使用 recover 的 goroutines。

runtime/pprof

allocmutexblockthreadcreategoroutine 的堆疊最大深度已從 32 個增為 128 個。框架。

runtime/trace

現在,執行時期會在程式因未捕捉到的恐慌而崩潰時明確刷新追蹤資料。這表示如果程式在追蹤進行時崩潰,追蹤中將會有更多完整的追蹤資料。

slices

Repeat 函數會傳回一新的切片,它會在給定的次數重複提供的切片。

sync

Map.Clear 方法會刪除所有條目,最後會得到一個空的 Map。它類似於 clear

sync/atomic

新的 AndOr 營運子會在給定的輸入套用位元 ANDOR,傳回舊值。

syscall

syscall 套件現在會在 Windows 上定義 WSAENOPROTOOPT

現在可以在 Windows 上支援 GetsockoptInt 函數。

testing/fstest

TestFS 現在會傳回一個結構化的錯誤,這個錯誤可以使用 errors.Unwrap 方法 (Unwrap() []error) 拆解。這讓我們可以使用 errors.Iserrors.As 來檢查錯誤。

text/template

範本現在支援新的「else with」動作,這可在某些使用案例中降低範本的複雜性。

time

現在,如果時區偏移出界, ParseParseInLocation 會傳回錯誤。

在 Windows 上,TimerTicker 和會讓 goroutine 進入休眠狀態的函數(例如 Sleep)的解析度已從 15.6ms 改進為 0.5ms。

unicode/utf16

RuneLen 函數傳回 UTF-16 編碼中符文的 16 位元組數。如果符文並非 UTF-16 編碼的有效值,將傳回 -1。

Darwin

如 Go 1.22 發行說明中 所公告,Go 1.23 需要 macOS 11 Big Sur 或更新版本;已停止支援先前的版本。

Linux

Go 1.23 是最後一個需要 Linux kernel 版本 2.6.32 或更新版本的發行版。Go 1.24 將需要 Linux kernel 版本 3.2 或更新版本。

OpenBSD

Go 1.23 新增 64 位 RISC-V 上 OpenBSD 的實驗性支援(GOOS=openbsdGOARCH=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 腳本已停止支援版本低于 14.0.0 的 wasmtime