Go 1.9 發行說明

Go 1.9 簡介

最新的 Go 發行版,版本 1.9,於 Go 1.8 六個月後發行,為 Go 1.x 系列 中的第 10 個發行版。共有兩項 語言變更:新增對類型別名的支援,並定義實作可以融合浮點數運算時機。大多數的變更都在於工具鏈、執行時間及函式庫的實作中。一如往常,此發行版維持 Go 1 相容性承諾。我們預期幾乎所有 Go 程式都可以像以前一樣繼續編譯及執行。

此發行版新增 透明單調時間支援、在 套件內並行編譯函式、更佳支援 測試輔助函式、包含一個新的 位元操作套件,且有一個新的 並發地圖類型

語言變更

共有兩項語言變更。

Go 現在支援類型別名,以在將類型從一個套件移動至另一個套件的同時支援逐漸程式碼修復。類型別名設計文件重構文章 詳細說明了此問題。簡而言之,類型別名的宣告格式如下:

type T1 = T2

此宣告會為 T2 所表示的類型新增一個別名名稱 T1(一個備用拼字),換言之,T1T2 都表示相同的類型。

比較小的語言變更部分,語言說明文件中現在寫明,當允許實作將浮點運算融合在一起時,例如使用架構的「融合乘法和加法」(FMA) 指令來計算 x*y + z,而無須捨入中間結果 x*y。如要強制執行中間捨入,請撰寫 float64(x*y) + z

移植

此版本沒有支援新的作業系統或處理器架構。

ppc64x 需要 POWER8

現在 GOARCH=ppc64GOARCH=ppc64le 都至少需要 POWER8 支援。在以前的版本中,只有 GOARCH=ppc64le 需要 POWER8,而 big endian ppc64 架構則支援較舊的硬體。

FreeBSD

Go 1.9 是最後一個能在 FreeBSD 9.3 上執行的版本,而 FreeBSD 9.3 已 不再受到 FreeBSD 支援。Go 1.10 將需要 FreeBSD 10.3+。

OpenBSD 6.0

Go 1.9 現在為 cgo 二進位檔案啟用 PT_TLS 產生,因此需要 OpenBSD 6.0 或更新的版本。Go 1.9 不再支援 OpenBSD 5.9。

已知問題

在 FreeBSD 中有一些不穩定狀況已知但尚未理解。在罕見情況下,這些狀況可能導致程式崩潰。請參閱 第 15658 個問題。任何有助於解決這個 FreeBSD 特有的問題的資訊都將深表感謝。

Go 在 Go 1.9 開發週期中停止執行 NetBSD 建構作業,原因在於發生了 NetBSD 核心崩潰,包括 NetBSD 7.1 在內。隨著 Go 1.9 的釋出,已釋出包括修正程式在內的 NetBSD 7.1.1。但是,目前我們的測試套件尚未通過任何 NetBSD 建構作業。任何有助於調查 各種 NetBSD 問題 的資訊都將深表感謝。

工具

平行編譯

Go 編譯器現在支援平行編譯套件函式,以利用多個核心。這除了讓 go 指令現有的平行編譯獨立套件的功能外,還新增了這些功能。平行編譯預設開啟,但可以透過設定環境變數 GO19CONCURRENTCOMPILATION0 來停用它。

與 ./… 搭配使用的供應商比對

根據普遍請求,./... 不再比對接受套件名稱的工具中的 vendor 目錄中的套件,例如 go test。如要比對供應商目錄,請撰寫 ./vendor/...

已搬移的 GOROOT

現在 go 工具 會使用呼叫它的路徑來嘗試尋找 Go 安裝樹根目錄。表示當整個 Go 安裝移到新位置時,go 工具應能照常繼續運作。這可以透過設定環境中的 GOROOT 來覆寫,不過這一般只會在特殊情況下才這麼做。請注意,這不會影響 runtime.GOROOT 函式的結果,該函式會持續回報原始安裝位置;在後續的版本中可能會修正這個問題。

編譯器工具鏈

複數除法現在已經相容於 C99。gccgo 始終都相容,而這個問題在 gc 工具鏈中已經修復。

連結器現在會為 Windows 上的 cgo 執行檔產生 DWARF 資訊。

如果提供了 -N -l 旗標,則編譯器現在會在產生的 DWARF 中包含詞彙範圍,使除錯器可以隱藏不在範圍內的變數。.debug_info 區段現在是 DWARF 4 版。

GOARMGO386 的值現在會影響已編譯套件的建置 ID,由 go 工具的相依性快取使用。

組譯器

四個運算元的 ARM MULA 指令現在已經正確組譯,第三個引數是加數暫存器,第四個(最後一個)引數是結果暫存器。在前幾個版本中,這兩個意義是相反的。第四個引數與第三個引數隱式相同的三個運算元格式並未受到影響。使用四個運算元 MULA 指令的程式碼需要更新,不過我們認為這種格式被使用的時機非常少。MULAWTMULAWB 已經在所有格式中使用正確的順序,且不予變更。

組譯器現在支援 ADDSUBPS/PD,完成缺少的兩個 x86 SSE3 指令。

文件

長串引數清單現在已經截斷。這可以改善 go doc 在某些產生的程式碼中讀取的能力。

現在支援結構欄位的說明文件檢視。例如,go doc http.Client.Jar

環境

新的 go env -json 旗標啟用 JSON 輸出,而非預設的特定於作業系統的輸出格式。

測試

go test 指令接受新的 -list 旗標,該旗標會將正規表示式作為引數,並將任何符合此表示式的測試、基準測試或範例名稱印出至標準輸出,而不會執行它們。

效能剖析工具

現在由 runtime/pprof 套件產生的剖析檔包含符號資訊,因此它們可以在 go tool pprof 中檢視,而不會使用產生剖析檔的二進位檔。

go tool pprof 指令現在使用環境中定義的 HTTP 代理資訊,使用 http.ProxyFromEnvironment

Vet

vet 指令 已更好地整合至 go 工具,所以 go vet 現在支援所有標準建置旗標,而 vet 本身旗標現在來自 go vetgo tool vet

Gccgo

因應 Go 半年度發行計畫與 GCC 年度發行計畫的一致性,GCC 版本 7 包含 Go 1.8.3 版的 gccgo。我們預期下一個版本 GCC 8 將包含 Go 1.10 版的 gccgo。

執行時期

包含內聯框架的呼叫堆疊

使用者應避免直接檢視 runtime.Callers 產生的 PC 片段,而應用 runtime.CallersFrames 取得完整的呼叫堆疊檢視,或應用 runtime.Caller 取得單一呼叫者的資訊。這是因為 PC 片段的個別元素無法說明內聯框架或呼叫堆疊的其他細微差別。

特別是直接反覆呼叫 PC 片段,並運用函數,例如 runtime.FuncForPC 個別解析各個 PC 的程式碼會遺漏內聯框架。若要取得堆疊的完整檢視,這樣的程式碼應改為使用 CallersFrames。同樣地,程式碼不應預設 Callers 回傳的長度是呼叫深度的任何指示。程式碼反之應計算 CallersFrames 回傳的框架數量。

在特定深度查詢單一呼叫者的程式碼應使用 Caller,而非傳遞一個長度為 1 的片段到 Callers

runtime.CallersFrames 已於 Go 1.7 起提供,所以程式碼可在升級到 Go 1.9 前更新。

效能

一如往常,變更極為普遍且多元,因此難以針對效能做出精確的陳述。大多數程式應會執行得略快一些,這歸功於垃圾搜集器的加速、更佳的產生程式碼,以及核心函式庫的最佳化。

垃圾搜集器

先前會引發停止世界的垃圾搜集的函式庫函數,現在會引發並行的垃圾搜集。特別是,runtime.GCdebug.SetGCPercentdebug.FreeOSMemory 現在會引發並行的垃圾搜集,僅在垃圾搜集完成前阻擋呼叫的 goroutine。

debug.SetGCPercent 函式僅於因新的 GOGC 值而必須立即進行一次垃圾回收時觸發一次垃圾回收。這使得能夠動態調整 GOGC。

針對使用含有許多大型物件的大型 (>50GB) 堆積的應用程式,大型物件的配置效能有大幅改進。

runtime.ReadMemStats 函式現在甚至對於非常大的堆積時間都不到 100µs。

標準函式庫

透明單調時間支援

time 套件現在會在每個 Time 值中透明追蹤單調時間,讓計算兩個 Time 值之間的持續時間變成了一個安全的作業,即使在調整時鐘時也不會有影響。請參閱套件文件設計文件以深入了解詳細資料。

新的位元操作套件

Go 1.9 包含新的套件 math/bits,具備最佳化位元操作實作方式。在大部分架構上,這個套件中的函式也會被編譯器辨識並視為本質,以獲得進一步的效能表現。

測試說明函式

新的 (*T).Helper(*B).Helper 方法將呼叫函式標記為測試說明函式。在列印檔案和行資訊時,該函式會被略過。這允許編寫測試說明函式,同時仍然具有對使用者來說有用的行號。

並行 Map

sync 套件中的新 Map 類型是一種非同步 Map,具有平攤常數時間的載入、儲存和刪除。多個 goroutine 可以同時呼叫 Map 的方法,也不會有安全上的疑慮。

剖析器標籤

runtime/pprof 套件現在支援將標籤新增至 pprof 剖析器記錄。標籤會形成一個金鑰對值,這個對值用於透過 pprof 指令在分析剖析結果時,區別在不同脈絡下呼叫同一個函式的差異。pprof 套件新的 Do 函式執行與某些提供的標籤相關聯的程式碼。套件中的其他新函式也協助處理標籤。

函式庫的次要變更

一如往常地,有各種次要的變更和更新套用到函式庫中,旨在考量 Go 1 中對相容性承諾

archive/zip

適當時,ZIP Writer 現在會在 FileHeader.Flags 中設定 UTF-8 位元組。

crypto/rand

在 Linux 上,Go 現在呼叫 `getrandom` 系統呼叫而不帶有 `GRND_NONBLOCK` 旗標;它現在會等候,直到核心具備足夠的隨機性。在早於 `getrandom` 系統呼叫的核心上,Go 會繼續從 `/dev/urandom` 進行讀取。

crypto/x509

在 Unix 系統上,環境變數 `SSL_CERT_FILE` 和 `SSL_CERT_DIR` 現在可分別用於覆寫 SSL 憑證檔案和 SSL 憑證檔案目錄的系統預設位置。

FreeBSD 檔案 `/usr/local/etc/ssl/cert.pem` 現在包含在憑證搜尋路徑中。

此套件現在支援名稱限制中的排除網域。除了強制執行這類限制外,CreateCertificate 也會建立具備排除名稱限制的憑證,如果所提供的範本憑證已填充新欄位 ExcludedDNSDomains

如果任何 SAN 擴充元,包括無 DNS 名稱,出現在憑證中,則從 Subject 來的公用名稱會被忽略。在先前的版本中,程式碼只測試憑證中是否存在 DNS 名稱 SAN。

database/sql

如果在 Tx.Stmt 中可取得已快取的 Stmt,則此套件現在會使用它。這麼做可以防止在每次呼叫 Tx.Stmt 時重新準備陳述式。

此套件現在允許驅動程式透過實作 driver.NamedValueChecker 來實作他們自己的引數檢查器。這麼做也允許驅動程式支援 `OUTPUT` 和 `INOUT` 參數類型。Out 應在驅動程式支援時用於傳回輸出參數。

Rows.Scan 現在可以掃描使用者的自訂字串類型。先前此套件支援掃描成數值類型,例如 `type` `Int` int64。現在它也支援掃描成字串類型,例如 `type` `String` string

新的 DB.Conn 方法傳回新的 Conn 類型,代表與資料庫的專屬連線,來自連線池。在 Conn 執行的所有查詢都會使用相同的基礎連線,直到呼叫 Conn.Close 將連線傳回連線池。

encoding/asn1

新的 NullBytesNullRawValue 代表 ASN.1 NULL 類型。

encoding/base32

新的 Encoding.WithPadding 方法增加了對自訂填充字元支援,並可停用填充。

encoding/csv

新的欄位 Reader.ReuseRecord 控制當呼叫 Read 時,是否會傳回一個區塊來共用上一個呼叫所傳回區塊的備份陣列,以提升效能。

fmt

列印浮點數和複數時,現在支援尖號旗標(’#’)。%e%E%f%F%g%G 將總是列印小數點,而 %g%G 也不會移除尾數零。

hash/fnv

此套件現在包括 128 位的 FNV-1 和 FNV-1a hash 支援,分別為 New128New128a

html/template

如果在通道中發現預先定義的 escape 函式(「html」、「urlquery」和「js」之一),但它與自動 escape 函式原本會決定的值不符,則此套件現在會報告錯誤。這可以避免某些安全性或正確性問題。現在使用其中一個 escape 函式,結果只會是無效操作或錯誤。(無效操作的案例可簡化從 text/template 的移轉。)

image

現在,Rectangle.Intersect 方法針對相鄰但沒有重疊的矩形(如文件所述)呼叫時,會傳回一個零 Rectangle。在早期版本中,它會不正確地傳回一個空的但非零 Rectangle

image/color

YCbCr 轉換為 RGBA 的公式已微調,以確保捨入調整涵蓋完整的 [0, 0xffff] RGBA 範圍。

image/png

新的 Encoder.BufferPool 欄位允許指定 EncoderBufferPool,它將由編碼器用於在編碼 PNG 影像時取得暫時的 EncoderBuffer 緩衝器。使用 BufferPool 可以減少在編碼多個影像時執行的記憶體配置次數。

此套件現在支援透明 8 位元灰階(「Gray8」)影像的解碼。

math/big

新的 IsInt64IsUint64 方法報告 Int 是否可以表示為 int64uint64 值。

mime/multipart

新的 FileHeader.Size 欄位描述多重訊息中檔案的大小。

net

新的 Resolver.StrictErrors 提供控制,以說明 Go 內建 DNS 解析器在處理由多個子查詢組成的查詢(例如 A+AAAA 位址查詢)期間,如何處理暫時性錯誤。

新的 Resolver.Dial 允許 Resolver 使用自訂的 dial 函式。

JoinHostPort 現在只會在主機包含冒號時,才將位址放在方括號內。在先前的版本中,如果位址包含百分比(’%’)符號,它也會用方括號將位址包起來。

新的方法 TCPConn.SyscallConnIPConn.SyscallConnUDPConn.SyscallConnUnixConn.SyscallConn 提供訪問連線基礎檔案描述符的能力。

現在,可以使用 `(*TCPListener).String()` 取得的地址安全地呼叫 Dial,前提是已經使用 `Listen(“tcp”, “:0”)` 建立聆聽器。先前,在某些機器上,若是 IPv6 堆疊僅半數組態好,就會失敗。

net/http

用於 CookieSet-Cookie 標頭的 Cookie.String 方法,如果值包含空白字元或逗號,現在會將值括在雙引號中。

伺服器變更

用戶端和傳輸變更

net/http/fcgi

新的 ProcessEnv 函式會回傳與 HTTP 請求相關的 FastCGI 環境變數,這些變數沒有對應的 http.Request 欄位,例如 REMOTE_USER

net/http/httptest

新的 Server.Client 方法會回傳設定好向測試伺服器發起請求的 HTTP 用戶端。

新的 Server.Certificate 方法會回傳測試伺服器的 TLS 憑證(如果有的話)。

net/http/httputil

ReverseProxy 現在會對所有 HTTP/2 回應尾端進行代理,甚至那些未在初始回應標頭中宣告的尾端。gRPC 協定會使用這些未宣告的尾端。

os

os 套件現在會使用內部的執行階段輪詢機制進行檔案 I/O。這會減少在管線中執行讀寫作業所需的執行緒數量,並且會消除當一個 goroutine 關閉檔案時,另一個 goroutine 正在使用該檔案執行 I/O 時所發生的競爭。

在 Windows 上,Args 現在會在不用 shell32.dll 的情況下填入,這會讓處理程序的啟動時間縮短 1-7 毫秒。

os/exec

os/exec 套件現在會防止子處理程序使用任何重複的環境變數建立。如果 Cmd.Env 包含重複的環境變數金鑰,那麼只會使用每個重複金鑰在區段中的最後一個值。

os/user

LookupLookupId 現在會在 CGO_ENABLED=0 時運用 Unix 系統透過讀取 /etc/passwd 檔案來運作。

LookupGroupLookupGroupId 現在會在 CGO_ENABLED=0 時運用 Unix 系統透過讀取 /etc/group 檔案來運作。

reflect

新的 MakeMapWithSize 函式會建立一個具有容量提示的映射。

runtime

執行階段產生的並記載在剖析中的追蹤記錄現在在內聯的情況下是精確的。如要以程式方式擷取追蹤記錄,應用程式應使用 runtime.CallersFrames,而不應直接反覆運算 runtime.Callers 的結果。

在 Windows 上,Go 不會再強制系統計時器在程式閒置時以高解析度執行。這應會降低 Go 程式對電池壽命的影響。

在 FreeBSD 上,GOMAXPROCSruntime.NumCPU 現在會根據處理程序的 CPU 遮罩,而非 CPU 的總數量來設定。

執行階段具有對 Android O 的初步支援。

runtime/debug

呼叫 runtime.SetGCPercent 並指定負值,不會再立即執行垃圾回收。

runtime/trace

執行緒追蹤現在會顯示標記協助事件,指出在應用程式 goroutine 因為分配速度太快而被迫協助垃圾回收的時間點。

「掃描」事件現在已涵蓋找尋可分配空間的整個流程,而非記錄已掃描的每一個區間。這會減少在追蹤具有大量分配的程式時分配的延遲。掃描事件會顯示已掃描及已回收的位元組數。

sync

Mutex 現在更公平。

syscall

新的欄位 Credential.NoSetGroups 會控制 Unix 系統在啟動新的處理程序時,是否會執行 setgroups 系統呼叫來設定補充性群組。

新的欄位 SysProcAttr.AmbientCaps 允許在 Linux 4.3+ 建立新程序時設定環境功能。

在 64 位元的 x86 Linux 中,使用 CLONE_VFORKCLONE_VM 最佳化了程序建立的延遲時間。

新的 Conn 介面會在 net 套件中描述一些類型,這些類型可以使用新的 RawConn 介面來取得其底層的檔案描述詞。

testing/quick

該套件現在會於產生 int64uint64 亂數時,從全部範圍中選擇數值;在早期版本中,產生的數值總是限制在 [-262, 262) 的範圍內。

在之前的版本中,使用一個 nil 的 Config.Rand 值會導致使用一個固定的決定性亂數產生器。現在改使用一種亂數產生器,並以目前時間作為種子。如需舊有的行為,請將 Config.Rand 設定為 rand.New(rand.NewSource(0))

text/template

空白區塊的處理方式是由於一個造成結果會依據範本順序而變的 Go 1.8 變更而中斷,現在已修復,並回復到舊有的 Go 1.7 行為。

time

新的方法 Duration.RoundDuration.Truncate 處理將持續時間四捨五入和取整數,以倍數表示一個給定的時間。

現在可以在 Wine 下正確地擷取時間和休眠。

如果一個 Time 值具有單調時鐘讀數,其字串表示形式(由 String 傳回)現在會包含一個最終欄位 "m=±value",其中 value 是以十進位數格式化的單調時鐘讀數,單位為秒。

所包含的 tzdata 時區資料庫已更新至 2017b 版本。與以往相同,如果系統中原本尚未有這份資料庫,才會使用這份資料庫。