還能這樣玩?Go 將會增強 Go1 向前相容性

煎魚發表於2023-01-30

大家好,我是煎魚。

年前我們在《醒醒吧,未來不會有 Go2 了!》文章中討論了 Go2 的未來,明確了未來是以 Go1.x.y 為主的 Go1 時代。

為了實現這個北極星目標,Go 團隊採取的策略分別是:增強 Go1 向後相容(在前文已分享)和 Go1 向前相容(本文重點內容)。

本次要提到的 “向前相容”,指的是舊版本的 Go 編譯新的 Go 程式碼。這個方向比較少被談論,甚至特意設計。

Go1 向前相容

Go 團隊的大當家 Russ Cox,針對如下幾個方面做了新設計和調整,輸出了《Proposal: Extended forwards compatibility in Go》,已經得到討論,很大機率落地。

部分重點如下:

  1. 新增 GOTOOLCHAIN 環境變數的設定。
  2. 改變在工作模組(work module)中解釋 go 行的方式,增加了新的工具鏈(toolchain)行。
  3. 對 go get 等命令進行聯動修改,允許對 GOTOOLCHAIN 和工作模組的 go 版本進行修改。

工作模組的 go.mod 和 toolchain

宣告 Go 版本號

我們會在 go module 生成時,在 Go 工程下生成一個 go.mod 檔案。其中會包含一個 go 行,將會宣告該模組應該應用的 go 版本語義是什麼版本。

如下圖,宣告的是 go1.13:

go.mod 檔案中的 go 版本宣告

在該提案落地後,本地安裝的 Go 工具鏈如果比 go 行所宣告的 go 版本新時,它將會直接提供所要求的舊語義,而不會重新下載和呼叫一箇舊版本的 Go 工具鏈。

但如果 go 行宣告瞭一個較新的 Go 工具鏈,那麼本地安裝的 Go 工具鏈就會下載並執行較新的工具鏈來滿足其需求。

以下是一個例子。

在例子中,我們正在執行的版本是 go1.30。但在模組中,有一個 go.mod 宣告瞭 go 版本:

go 1.30.1

Go1.30 會下載並呼叫 go1.30.1 來完成命令,因為模組中要求的 go 版本比本地安裝的更高。

但如果 go.mod 檔案中宣告的是:

go 1.20rc1

Go1.30 將自己提供 go1.20rc1 語義,而不是執行 go1.20 rc1 工具鏈。因為本地安裝的版本更新,可以透過 GODEBUG 來滿足舊語義的訴求。

宣告 Go 工具鏈版本號

可能會有同學想要執行更新版本的 Go 工具鏈,但 Go 語義上還是使用舊版本。

為了滿足這點訴求,go.mod 檔案也會支援 toolchain 行的設定,以此來支援新版本的工具鏈的使用。

如果 go.mod 檔案中設定了 toolchain 行,將指定使用的工具鏈版本,go 行只指定語言語義的 Go 版本。

go.mod 檔案如下:

go 1.18
toolchain go1.20rc1

作用是將為這個模組選擇 go1.18 的語義,使用 go1.20rc1 的工具鏈來構建應用。

Go 工具鏈 GOTOOLCHAIN

將會在 Go 工具鏈新增 GOTOOLCHAIN 環境變數的設定和使用可以使用 go env -w 設定。也可以在 go test 時做如下調整:

GOTOOLCHAIN=go1.17.2 go test

go build 編譯時可以:

GOTOOLCHAIN=go1.18rc1 go build -o myprog.exe

可能會有同學疑惑 GOTOOLCHAIN 的預設值哪來,有哪些值?

  • 設定 GOTOOLCHAIN=local:使用本地安裝的 Go 工具鏈,不會下載不同版本的工具鏈。這是現在的的預設行為。
  • 設定 GOTOOLCHAIN=auto:使用工作模組的 go.mod 中宣告的 go 版本(當它比本地安裝的 Go 工具鏈要新時)。

GOTOOLCHAIN 環境變數的預設值取決於 Go 工具鏈。標準 Go 發行版預設為 GOTOOLCHAIN=auto,也就是將控制權交給 go.mod 檔案。這是在實施這個提案後 99% 會看到的預設行為。

Go 工具鏈的一攬子東西里也比較多,例如:go get 命令,也會對 go.mod 檔案中的 go 版本或 toolchain 行進行變更,以配合使用。

總結

在今天這篇文章中,我們介紹了 Go1 相容性增強中的 “向前相容” 部分,其中要點是:加大對 go.mod 檔案中的 go 行和 toolchain 行和工具鏈 GOTOOLCHAIN 相關的應用。

核心目的是為了將 go 語法語義和 go 工具鏈的版本宣告公開出來,達到隔離使用。再配合 “向後相容” 中的 GODEBUG 的使用,讓 Go 語言做相容性時有更多更大的使用空間來實現機制上的保障。

這麼一來,Go 語言在這一塊會變得異常複雜,理解成本也會變高。希望大家後續在這塊也不要再踩坑了。

文章持續更新,可以微信搜【腦子進煎魚了】閱讀,本文 GitHub github.com/eddycjy/blog 已收錄,學習 Go 語言可以看 Go 學習地圖和路線,歡迎 Star 催更。

Go 圖書系列

推薦閱讀

相關文章