Go 1.5 發行說明

Go 1.5 簡介

最新推出的 Go 1.5 版為重大版本,包含實作的重大變動。儘管如此,我們預期幾乎所有 Go 程式都能如往常一樣繼續編譯並執行,因為此版本仍維持 Go 1 相容性承諾

實作的最大變更如下

底下會說明上述這些以及對執行環境和工具的其他多項變更。

此次推出的版本還包含與映射文字相關的一個小型的語言變更。

最後,發行 時程與既有的六個月間隔有所出入,目的是提供更多時間來準備此次重大版本更新,並且將時程表稍作調整,讓推出日期更恰當。

語言變更

映射文字

由於一個疏忽,允許省略切片文字中元素類型的規則並未套用於映射鍵。已在 Go 1.5 中更正此問題。透過以下範例會較清楚。從 Go 1.5 開始,這個映射文字,

m := map[Point]string{
    Point{29.935523, 52.891566}:   "Persepolis",
    Point{-25.352594, 131.034361}: "Uluru",
    Point{37.422455, -122.084306}: "Googleplex",
}

可以改寫如下,而不必明文列出 Point 類型

m := map[Point]string{
    {29.935523, 52.891566}:   "Persepolis",
    {-25.352594, 131.034361}: "Uluru",
    {37.422455, -122.084306}: "Googleplex",
}

執行環境

不再有 C

編譯器和執行環境現在是用 Go 和組譯器來執行的,不含 C。樹中唯一剩下的 C 原始碼與測試或 cgo 有關。樹中在 1.4 和之前版本中都有 C 編譯器。它用來建置執行環境;而自訂編譯器有部分原因是必要的,因為這樣才能確保 C 程式碼會配合 goroutine 的堆疊管理。由於執行環境改用 Go,因此無需使用此 C 編譯器,所以它已被移除。已在其他地方討論如何移除 C 的過程詳情。

使用專門為此工作建立的自訂工具來執行從 C 轉換的工作。最重要的一點是,編譯器實際上已自動將 C 程式碼轉譯成 Go 程式碼。它實際上是不同語言下相同的程式。它並非編譯器的新執行環境,因此我們預期這個過程不會衍生新的編譯器 bug。有關此過程的概觀,已提供在此簡報的投影片中。

編譯器和工具

儘管獨立於轉移 Go,但受到此轉移的激勵,這些工具的名稱已變更。舊名稱 6g8g 等已移除;取而代之的是只有一個二進位檔,可用 go tool compile 存取,它會將 Go 原始碼編譯成適用於由 $GOARCH$GOOS 指定之架構和作業系統的二進位檔。同樣地,現在只有一個連結器(go tool link)和一個組譯器(go tool asm)。連結器是由舊 C 執行環境自動轉譯而來,但組譯器是新的原生 Go 執行環境,詳情會在下方討論。

類似移除名稱 6g8g 等的做法,編譯器和組譯器的輸出現在給予一個單純的 .o 字尾,而非 .8.6 等。

垃圾回收器

垃圾回收器已重新設計為 1.5,這是 設計文件 中所述開發的一部份。與舊版發行版的收集器的預估延遲時間相較之下,透過先進演算法、更好的收集器 排程,以及與使用者程式並行執行更多收集,預估延遲時間減少許多。收集器的「停止世界」階段幾乎永遠低於 10 毫秒,而且通常要低很多。

對於可受益於低延遲時間的系統,例如使用者反應式網站,使用新的收集器讓預估延遲時間下降可能很重要。

新的收集器的詳細資料呈現於 2015 年 GopherCon 的演說中。

執行時期

在 Go 1.5 中,goroutine 的排程順序已變更。排程器的屬性未曾由語言定義,但仰賴排程順序的程式可能會因為這個變更而中斷。我們已看到少數因為這個變更而受影響的(錯誤)程式。如果您有程式隱含仰賴排程順序,您需要更新它們。

另一個會中斷的變更可能是執行時期現在會設定同時執行緒程數量的預設值,由 GOMAXPROCS 定義,為 CPU 上可用核心數量。在舊版發行版中,預設值為 1。未預期與多個核心一起執行的程式可能會意外中斷。它們可以透過移除限制或明確設定 GOMAXPROCS 來更新。如需有關這個變更的更詳細討論,請參閱設計文件

建置

由於 Go 編譯器和執行時期是使用 Go 撰寫的,所以必須要有 Go 編譯器才能從原始碼編譯發行版。因此,要建立 Go 核心,必須先備妥可使用的 Go 發行版。(不受核心影響的 Go 程式設計師不受這個變更影響。)任何 Go 1.4 或更新版本發行版(包括 gccgo)都可以使用。有關詳細資料,請參閱設計文件

移植

由於產業大部分已經擺脫 32 位元 x86 架構,1.5 中提供的二進位下載套件減少了。僅提供適用於 OS X 作業系統的 amd64 架構發行版,沒有提供 386。類似地,Snow Leopard(Apple OS X 10.6)的移植仍然可以使用,但不再以下載形式釋出或維護,因為 Apple 不再維護作業系統的這個版本。此外,dragonfly/386 移植不再受到支援,這是因為 DragonflyBSD 本身已不再支援 32 位元 386 架構。

不過,現在提供了好幾個新的移植可以從原始碼建立。這些包括 darwin/armdarwin/arm64。新的移植 linux/arm64 大多已就定位,但是 cgo 僅支援使用外部分址連結。

此外,也以實驗方式提供了 ppc64ppc64le(64 位元 PowerPC,大端和低端)。這兩個移植都支援 cgo,但是僅支援內部連結。

在 FreeBSD 上,Go 1.5 需要 FreeBSD 8-STABLE+,因為它採用了新的 SYSCALL 指令。

在 NaCl 上,Go 1.5 需要 SDK 版本 pepper-41。後續 pepper 版本不支援,因為已從 NaCl 執行階段中移除 sRPC 子系統。

在 Darwin 上,使用系統 X.509 憑證介面可以用 ios build 標籤停用。

Solaris 埠現在完全支援 cgo 和套件 netcrypto/x509,還有其他許多修正和改進。

工具

轉譯

消除 C 語言的程式碼過程中,編譯器和連結器已由 C 語言轉譯成 Go。那是一次真正的(電腦輔助的)轉譯,所以新的程式本質上是已經轉譯過的舊程式,而不是有新 bug 的新程式。我們相信轉譯過程只產生少數的新 bug,如果有,而且實際上還發現了許多先前未知的 bug,現在問題已解決了。

然而,組譯器是一個新的程式;它在下面有說明。

重新命名

編譯器組合程式(例如 6g8g 等)、組譯器組合程式(例如 6a8a 等)和連結器組合程式(例如 6l8l 等)已整合到一個單一的工具,它會根據環境變數 GOOSGOARCH 來設定。舊名稱已經移除;新的工具可以使用 go tool 機制作為 go tool compilego tool asmgo tool link 存取。此外,中間物件檔案的檔案附檔名 .6.8 等也已移除;現在它們只是單純的 .o 檔案。

例如,要使用工具直接編譯並連結位於 amd64 上的 Darwin 程式,而不是透過 go build,可以執行下列動作

$ export GOOS=darwin GOARCH=amd64
$ go tool compile program.go
$ go tool link program.o

移動

由於 go/types 套件現在已移入主要資料庫(請參閱下方),vetcover 工具也已被移入。它們不再保留於外部 golang.org/x/tools 資料庫,雖然(已棄用的)原始碼仍然放在那裡,以便與舊版相容。

編譯器

如上所述,Go 1.5 中的編譯器是一個單一的 Go 程式,由舊的 C 語言原始碼轉譯而來,取代了 6g8g 等等。它的目標會根據環境變數 GOOSGOARCH 來設定。

1.5 編譯器大部分與舊編譯器相同,但有些內部細節已變更。其中一項重大變更為常數的評估現使用 math/big 套件,而非自訂(且測試較少)的高精度運算實作。我們預期這不會影響結果。

僅限 amd64 架構,編譯器新增一個新的選項 -dynlink,透過支援對外部共用程式庫中定義的 Go 符號的參考,協助動態連結。

組譯器

與編譯器和連結器一樣,Go 1.5 中的組譯器是一個單一程式,取代了一組組譯器(6a8a 等)及環境變數 GOARCHGOOS,用來設定架構和作業系統。與其他程式不同之處在於,組譯器是一個全新的以 Go 編寫的程式。

新組譯器與前一個版本幾乎相容,但有些變更可能影響某些組譯器原始檔。請參閱更新的 組譯器指南,以取得關於這些變更的更具體資訊。總而言之

首先,用於常數的表示式評估稍微有所不同。它現在使用未簽署 64 位元運算,而且運算子(+-<< 等)的優先順序來自 Go,而非 C。我們預期這些變更僅影響少數程式,但可能需要手動驗證。

有更重大的一點是,在 SPPC 僅為某個編號暫存器的別名(例如 ARM 上堆疊指標為 R13、硬體程式計數器為 R15)的機器上,如果對此類暫存器的參考不包含符號,則為非法。例如,SP4(SP) 為非法,但 sym+4(SP) 為合法。在此類機器上,若要參照硬體暫存器,請使用其真正的 R 名稱。

一處較小的變更為一些舊組譯器允許下列表示法

constant=value

來定義一個命名常數。由於總是可以用傳統的類 C #define 表示法執行此動作(仍然得到支援,組譯器包含簡化 C 前處理器的實作),因此該功能已被移除。

Go 1.5 中的連結器現在是一個 Go 程式,用以取代 6l8l 等。其作業系統和指令集由環境變數 GOOSGOARCH 指定。

還有數項其他變更。其中最重要的是新增 -buildmode 選項,擴充連結的樣式;它現在支援各種情況,例如建置共用程式庫,並允許其他語言呼叫 Go 程式庫。其中一些已在 設計文件 中列出。若要取得可用建置模式及其用途的清單,請執行

$ go help buildmode

另一個改變是連結器不再記錄建立時間戳記於 Windows 可執行檔的標頭中。另外,儘管這可能已被修正,但 Windows cgo 可執行檔會遺失部分 DWARF 資訊。

最後,-X 旗標會帶兩個參數,如下所示:

-X importpath.name value

現在也會採用更常見的 Go 標旗風格,只有一個 name=value 配對的參數

-X importpath.name=value

儘管舊的語法仍然有效,但建議於指令碼等地方使用的這個旗標已更新為新的樣式。

Go 指令

go 指令的基本運作沒有改變,但有許多值得注意的變更。

前一個版本曾提出一個概念,即指令中一個目錄內部的封裝無法匯入。在 1.4 中,它以核心資料庫中一些內部元素的引入來進行測試。正如 設計文件 中所建議的,該變更現已適用於所有資料庫。規則在設計文件中進行了解釋,不過總結來說,任何封裝位於或少於名為 internal 的目錄中,都可以由根於相同子樹中的封裝來匯入。具有名為 internal 的目錄元素的現有封裝可能會因這個變更而意外中斷,這也是它在最後一個版本中宣傳的原因。

處理封裝的另一個變更則為增強對「供應商」的實驗性支援。詳情請參閱 go 指令設計文件

也有許多微小的變更。請閱讀 文件 以取得完整詳細資料。

Go vet 指令

go tool vet 指令現可更徹底地驗證結構標籤。

Trace 指令

有新工具可用於動態執行 Go 程式的追蹤。使用方法類似於測試涵蓋率工具的運作方式。追蹤的產生已整合到 go test 中,然後追蹤工具本身的個別執行會分析結果。

$ go test -trace=trace.out path/to/package
$ go tool trace [flags] pkg.test trace.out

旗標可啟用在瀏覽器視窗中顯示輸出。如需詳細資料,請執行 go tool trace -help。在此 演講 中也有追蹤功能的說明,此演講來自 2015 年 GopherCon。

Go doc 指令

幾個版本前,go doc 指令已刪除,因為似乎沒有必要。您隨時可以使用 godoc . 來取代。1.5 版引進新的 go doc 指令,其命令列介面較 godoc 方便,而且專門設計用於命令列,旨在提供更精簡、重點聚焦於套件或其組成的元素的文件。其呼叫方式也會有所不同,此外,它還提供不分大小寫的比對和顯示未匯出符號文件的支援。如需詳細資料,請執行 go help doc

Cgo

解析 #cgo 行時,呼叫 ${SRCDIR} 現已擴充到原始程式碼目錄路徑。這麼一來,就可以將選項傳遞給編譯器和連結器,而這些選項涉及原始程式碼目錄的相關檔案路徑。未進行擴充路徑就會無效,因為目前的作業目錄會變更。

Solaris 現在支援完整的 cgo。

在 Windows 中,cgo 現在預設使用外部連結。

如果 C 結構以零大小的欄位結束,但結構本身不是零大小,Go 程式碼就無法再參照零大小的欄位。任何此類參照都必須改寫。

效能

一如既往,變數變化如此普遍且多樣化,實在很難做出精準的效能說明。此版本中的變動範圍比往常更廣,其中包含新的記憶體回收器以及將執行時間轉換為 Go。有些程式可能會執行得更快,有些則較慢。平均而言,Go 1基準套件中的程式在 Go 1.5 中執行的速度比 Go 1.4 快了 2%,同時如上述所述,記憶體回收器的暫停時間明顯縮短,而且幾乎都低於 10 毫秒。

在 Go 1.5 中建立的速度會變慢,大約慢 2 倍。自動將編譯器和連結器從 C 轉換為 Go 會產生不慣用的 Go 程式碼,與編寫完善的 Go 程式碼相比,效能很差。分析工具和重構有助於改善程式碼,但仍有許多工作待完成。後續將會在 Go 1.6 和未來版本中繼續進行剖析和最佳化。欲知更多詳細資訊,請參閱下列投影片和相關影片

標準函式庫

標記

PrintDefaults函式(以及FlagSet的方法)在 flag 套件中經過修改,可產生更友善的使用狀況訊息。格式已變更為更人性化,在使用狀況訊息中,用反引號 `` 標示的文字視為標記運算元的顯示名稱。例如,建立標記的呼叫會顯示

cpuFlag = flag.Int("cpu", 1, "run `N` processes in parallel")

說明訊息,

-cpu N
        run N processes in parallel (default 1)

此外,預設值現在只會在不是該型別的 0 值時才會顯示。

math/big 中的浮點數

math/big套件有新的基本資料型別Float,用於執行任意精確度的浮點數。Float 值由布林位元組、可變長度的尾數以及 32 位元固定大小的帶正負號數值組成。Float 的精確度(尾數的大小,以位元為單位)可以明確指定,或由產生該值的第一次運算所決定。建立後,Float 的尾數大小可以使用SetPrec方法來修改。Floats支援無限概念,例如是由溢位所產生,但會產生等效於 IEEE 754 NaN 的值會引發例外狀況。Float運算支援所有 IEEE-754 捨入模式。當精度設定為 24 (53) 位元時,在標準化float32 (float64) 值範圍內執行的運算會產生與這些值的 IEEE-754 算術相同的結果。

Go 型別

到目前為止,go/types 套件一直維護在 golang.org/x 儲存庫中;從 Go 1.5 開始,它已移至主儲存庫中。舊位置的程式碼現已過時。套件中還有一個適度的 API 變更,詳見下文。

隨著此移動動作,go/constant 套件也移至主儲存庫中;之前它是 golang.org/x/tools/exact。同理,go/importer 套件也移至主儲存庫,以及上面介紹的一些工具。

Net

Net 套件中的 DNS 解析器幾乎經常使用 cgo 來存取系統介面。Go 1.5 中的變更表示在大部分 Unix 系統中,DNS 解析將不再需要 cgo,這簡化了在這些平台上的執行。現在,如果系統的網路組態允許,本機 Go 解析器就足夠了。此變更的重要影響是每次 DNS 解析都佔用一個 goroutine,而不是一個執行緒,因此具有多個未完成 DNS 要求的程式將消耗較少的作業系統資源。

關於如何執行解析器的決策套用於執行時間,而不是建置時間。用於強制使用 Go 解析器的 netgo 建置標籤不再需要,儘管它仍然有效。新的 netcgo 建置標籤會在建置時間強制使用 cgo 解析器。要在執行時間強制執行 cgo 解析,請在環境中設定 GODEBUG=netdns=cgo。更多的除錯選項的文件記載於這裡

此變更僅適用於 Unix 系統。Windows、Mac OS X 和 Plan 9 系統的行為與以往相同。

Reflect

reflect 套件新增兩個函式:ArrayOfFuncOf。這些函式類似於現有的 SliceOf 函式,在執行時間建立新的類型來描述陣列和函式。

強化

透過使用go-fuzz 工具進行亂數測試,已在標準程式庫中找到數十個 bug。這些 bug 已在 archive/tararchive/zipcompress/flateencoding/gobfmthtml/templateimage/gifimage/jpegimage/pngtext/template 套件中修復。這些修正強化了實作,以對抗不正確和惡意的輸入。

程式庫的次要變更