Go 部落格
Go 1.21 中的向前相容性和工具鏈管理
除了 Go 1.21 中對向後相容性的擴充套件承諾之外,Go 1.21 還為 Go 程式碼引入了更好的向前相容性,這意味著 Go 1.21 及更高版本將更謹慎地避免錯誤編譯需要更新 Go 版本才能執行的程式碼。具體來說,go.mod
檔案中的 go
行現在指定了所需的最低 Go 工具鏈版本,而在之前的版本中,這主要是一個未強制執行的建議。
為了更輕鬆地跟上這些要求,Go 1.21 還引入了工具鏈管理,這樣不同的模組就可以使用不同的 Go 工具鏈,就像它們可以使用不同版本的所需模組一樣。安裝 Go 1.21 後,您將再也不必手動下載和安裝 Go 工具鏈。go
命令可以為您完成。
本文的其餘部分將更詳細地介紹 Go 1.21 中的這兩項更改。
向前相容性
向前相容性是指 Go 工具鏈嘗試構建為較新 Go 版本設計的 Go 程式碼時發生的情況。如果我的程式依賴於模組 M,並且需要 M v1.2.3 中新增的 bug 修復,我可以在我的 go.mod
檔案中新增 require M v1.2.3
,以確保我的程式不會與 M 的舊版本一起編譯。但是,如果我的程式需要特定版本的 Go,則一直沒有表達這種需求的方法:特別是,go.mod
檔案中的 go
行並未表達這一點。
例如,如果我編寫了使用 Go 1.18 中新增的泛型的程式碼,我可以在我的 go.mod
檔案中寫 go 1.18
,但這並不能阻止 Go 的早期版本嘗試編譯該程式碼,從而產生類似以下錯誤的編譯錯誤:
$ cat go.mod
go 1.18
module example
$ go version
go version go1.17
$ go build
# example
./x.go:2:6: missing function body
./x.go:2:7: syntax error: unexpected [, expecting (
note: module requires Go 1.18
$
這兩個編譯錯誤都是誤導性的噪音。真正的問題由 go
命令作為提示打印出來:程式編譯失敗,因此 go
命令指出了潛在的版本不匹配。
在此示例中,我們很幸運構建失敗了。如果我編寫的程式碼只能在 Go 1.19 或更高版本中正確執行,因為它依賴於該補丁版本中修復的 bug,但我在程式碼中沒有使用任何 Go 1.19 特定的語言功能或包,那麼 Go 的早期版本將編譯它並靜默成功。
從 Go 1.21 開始,Go 工具鏈將 go.mod
檔案中的 go
行視為規則而非指導方針,並且該行可以列出特定的次要版本或候選版本。也就是說,Go 1.21.0 知道它甚至不能構建在 go.mod
檔案中宣告 go 1.21.1
的程式碼,更不用說宣告 go 1.22.0
等更晚版本了。
我們允許舊版本的 Go 嘗試編譯新程式碼的主要原因是為了避免不必要的構建失敗。當被告知您的 Go 版本太舊而無法構建程式時,尤其令人沮喪,特別是當它可能仍然有效(也許需求過於保守)時,並且尤其當更新到新版本的 Go 版本有些麻煩時。為了減少將 go
行強制作為要求的負面影響,Go 1.21 還將工具鏈管理新增到核心發行版中。
工具鏈管理
當您需要新版本的 Go 模組時,go
命令會為您下載它。從 Go 1.21 開始,當您需要新的 Go 工具鏈時,go
命令也會為您下載。此功能類似於 Node 的 nvm
或 Rust 的 rustup
,但它是內建在核心 go
命令中的,而不是一個單獨的工具。
如果您正在執行 Go 1.21.0,並且在具有宣告 go 1.21.1
的 go.mod
檔案的模組中執行 go build
等 go
命令,則 Go 1.21.0 的 go
命令會注意到您需要 Go 1.21.1,下載它,然後重新呼叫該版本的 go
命令來完成構建。當 go
命令下載和執行這些其他工具鏈時,它不會將它們安裝到您的 PATH 中,也不會覆蓋當前安裝。相反,它將它們作為 Go 模組下載,繼承模組的所有安全和隱私優勢,然後從模組快取中執行它們。
go.mod
檔案中還有一個新的 toolchain
行,用於指定在特定模組中工作時使用的最低 Go 工具鏈。與 go
行不同,toolchain
不會對其他模組施加要求。例如,一個 go.mod
檔案可能宣告
module m
go 1.21.0
toolchain go1.21.4
這表示其他需要 m
的模組需要提供至少 Go 1.21.0,但當我們在 m
本身中工作時,我們想要一個更更新的工具鏈,至少是 Go 1.21.4。
go
和 toolchain
要求可以使用 go get
以與普通模組要求相同的方式進行更新。例如,如果您正在使用 Go 1.21 的候選版本之一,您可以透過執行以下命令在一個特定模組中開始使用 Go 1.21.0:
go get go@1.21.0
這將下載並執行 Go 1.21.0 來更新 go
行,並且將來呼叫 go
命令時將看到 go 1.21.0
行並自動重新呼叫該版本。
或者,如果您想在一個模組中使用 Go 1.21.0,但將 go
行保留為舊版本,以幫助維護與早期 Go 版本使用者的相容性,您可以更新 toolchain
行:
go get toolchain@go1.21.0
如果您想知道在特定模組中執行的 Go 版本是什麼,答案與以前相同:執行 go version
。
您可以使用 GOTOOLCHAIN 環境變數強制使用特定的 Go 工具鏈版本。例如,要使用 Go 1.20.4 測試程式碼:
GOTOOLCHAIN=go1.20.4 go test
最後,GOTOOLCHAIN 設定的形式為 version+auto
,表示預設使用 version
,但允許升級到更新的版本。如果您已安裝 Go 1.21.0,那麼當 Go 1.21.1 釋出時,您可以透過設定預設 GOTOOLCHAIN 來更改系統預設值:
go env -w GOTOOLCHAIN=go1.21.1+auto
您將再也不必手動下載和安裝 Go 工具鏈。go
命令會為您處理。
有關更多詳細資訊,請參閱“Go Toolchains”。
下一篇文章:使用 slog 進行結構化日誌記錄
上一篇文章:向後相容性、Go 1.21 和 Go 2
部落格索引