Go 1.11 發行說明

Go 1.11 簡介

最新的 Go 版本 1.11 在 Go 1.10 六個月後發布。大部分變更在於工具鏈、執行時期與函式庫的實作。如同往常,版本會維持 Go 1 相容性承諾。我們預期幾乎所有 Go 程式都能如以往編譯和執行。

語言變更

語言規格沒有變更。

移植

正如 Go 1.10 發行說明 所公告的,Go 1.11 現在需要 OpenBSD 6.2 或更新版本,macOS 10.10 Yosemite 或更新版本,或 Windows 7 或更新版本;已移除對這些作業系統先前版本的支援。

Go 1.11 支援即將推出的 OpenBSD 6.4 版本。由於 OpenBSD 核心變更,較舊版本的 Go 將無法在 OpenBSD 6.4 上執行。

在 i386 硬體環境中,NetBSD 有 已知問題

競爭條件偵測器現在支援 linux/ppc64le,程度較低,也支援 netbsd/amd64。NetBSD 競爭條件偵測器支援有 已知問題

記憶體清除器 (-msan) 現在支援 linux/arm64

組建模式 c-sharedc-archive 現在支援 freebsd/amd64

在 64 位元 MIPS 系統上,新的環境變數設定「GOMIPS64=hardfloat」(預設值)和「GOMIPS64=softfloat」,用於在浮點運算中選擇是使用硬體指令或軟體模擬。在 32 位元系統中,環境變數仍然是「GOMIPS」,如 Go 1.10 中新增

在軟浮點 ARM 系統(「GOARM=5」)上,Go 現在使用較有效率的浮點軟體介面。對 Go 程式碼而言這部份是透明的,但 ARM 組合語言會使用未在 GOARM 中保護的浮點指令,且必須移植到 新介面

在 ARMv7 上的 Go 1.11 不再需要設定成使用「KUSER_HELPERS」的 Linux 核心。預設的核心設定中已啟用此設定,但在簡化的設定中有時會停用它。

WebAssembly

Go 1.11 新增了一個實驗性傳輸埠到 WebAssembly(「js/wasm」)。

Go 程式目前編譯成一個 WebAssembly 模組,其中包括用於 Goroutine 排程、垃圾回收、映射等的 Go 執行時期。因此,產生的尺寸至少約為 2 MB 或壓縮後的 500 KB。Go 程式可以使用新的實驗性 syscall/js 套件呼叫 JavaScript。二進位尺寸和與其他語言的互操作性尚未列為優先事項,但可以在未來的發行版本中處理。

由於新增了新的「GOOS」值「js」和「GOARCH」值「wasm」,現在「*_js.go」或「*_wasm.go」的 Go 檔案將會在使用這些 GOOS/GOARCH 值時 被 Go 工具忽略。如果您有符合這些模式的現有檔案名稱,則需要重新命名它們。

可以在 WebAssembly 維基頁面 上找到更多資訊。

預留的 RISC-V GOARCH 值

主要的 Go 編譯器尚未支援 RISC-V 架構。但是我們已經預留「riscv」和「riscv64」的「GOARCH」值,而 Gccgo 會使用這些值,Gccgo 支援 RISC-V。這表示現在「*_riscv.go」的 Go 檔案也會在使用這些 GOOS/GOARCH 值時 被 Go 工具忽略

工具

模組、套件版本化和相依性管理

Go 1.11 為一個名為「模組」的 新概念新增初步支援,它是 GOPATH 的替代方案,結合了版本化和套件散布的內建支援。使用模組後,開發人員不再侷限於在 GOPATH 內部工作,版本相依性的資訊是明確且輕量的,而建置也更可靠,可重複性也更高。

模組支援被視為實驗性質。根據 Go 1.11 使用者的回饋,可能會變更詳細資料,且我們已規劃更多工具。雖然模組支援的詳細資料可能變更,但使用 Go 1.11 轉換到模組的專案將繼續適用於 Go 1.12 及後續版本。如果您在使用模組時遇到錯誤,請提出問題 報告問題,以便我們能解決問題。更多資訊請參閱 go 命令文件

匯入路徑限制

由於 Go 模組支援在命令列操作中賦予特殊意義給 @ 符號,因此 go 指令現在禁止使用包含 @ 符號的匯入路徑。go get 原本就不允許此類匯入路徑,因此此限制只會影響透過其他方式建立自訂 GOPATH 樹的使用者。

套件載入

新的套件 golang.org/x/tools/go/packages 提供一個簡單的 API,用於尋找和載入 Go 原始碼套件。雖然尚未成為標準程式庫的一部分,但對於許多任務來說,它有效地取代 go/build 套件,後者的 API 無法完全支援模組。由於它會執行外部查詢指令如 go list 來取得關於 Go 套件的資訊,因此它能建立分析工具,讓替代建構系統如 BazelBuck 能夠同樣順利運作。

建置快取需求

Go 1.11 將是最後支援將環境變數 GOCACHE=off 設為停用 建置快取 的版本(建置快取是在 Go 1.10 中引入)。從 Go 1.12 開始,建置快取將成為必要的步驟,朝著移除 $GOPATH/pkg 邁進。上文所述的模組和套件載入支援,已經需要啟用建置快取。如果您已停用建置快取以避免遇到問題,請提出問題 報告問題,讓我們了解問題所在。

編譯器工具鏈

更多的函數現在符合內嵌的預設條件,包括呼叫 panic 的函數。

編譯器工具鏈現在支援 行指令 中的欄位資訊。

一個新的封裝匯出資料格式已經介紹。這對最終用戶來說應該是透明的,除了加快大型 Go 專案的建置時間之外。如果真的造成問題,可在建置二進位檔案時,透過傳遞 -gcflags=all=-iexport=falsego 工具來關閉它。

編譯器現在會拒絕在類型轉換保護中宣告的未用變數,例如在以下範例的 x

func f(v interface{}) {
    switch x := v.(type) {
    }
}

這已經遭到 gccgogo/types 拒絕。

組譯器

amd64 的組譯器現在接受 AVX512 指令。

除錯

編譯器現在產生更多明顯的正確除錯資訊,用於最佳化的二進位檔案,包括變數位置資訊、行數和中斷點位置。透過這個方法才能除錯沒有 -N -l 編譯的二進位檔案。除錯資訊品質仍有其限制,其中有些是基本的,其他則是會持續提升至往後發布的版本中。

DWARF 區段現在是預設壓縮,因為是由編譯器產生的擴充及更準確的除錯資訊。這種方法對大多數 ELF 工具來說是透明的(例如 Linux 和 *BSD 上的除錯器),且受到所有平台上的 Delve 除錯器的支援,但對於 macOS 和 Windows 上的原生工具而言,支援有限。若要停用 DWARF 壓縮,請在建置二進位檔案時,傳遞 -ldflags=-compressdwarf=falsego 工具。

Go 1.11 加入從除錯器呼叫 Go 函式的實驗性支援。這會有用處,舉例而言,在中斷點暫停時呼叫 String 方法。目前僅 Delve(1.1.0 版及其以後版本)支援這個功能。

測試

自 Go 1.10 以來,go test 命令在套件上執行 go vet 來識別問題,然後才執行測試。由於 vet 會先使用 go/types 對程式碼進行型別檢查,執行測試之前,執行型別檢查失敗的測試現在將會失敗。尤其是包含在使用 Go 1.10 編譯的封閉中,未使用的變數的測試,因為 Go 編譯器錯誤地接受它們(第 3059 號問題),但現在將會失敗,因為 go/types 在這種狀況下正確回報「未使用的變數」錯誤。

現在 go test-memprofile 旗標預設為「allocs」設定檔,記錄測試開始以來分配的總位元組數(包括垃圾回收位元組)。

驗證

go vet 命令在分析套件中沒有執行型別檢查時,現在會回報致命錯誤。之前,型別檢查錯誤只會導致列印出警告,且 vet 會以狀態 1 離開。

另外,go vet 在執行格式檢查 printf 包裝器時變得更为強大。Vet 現在可以偵測到範例中的錯誤

func wrapper(s string, args ...interface{}) {
    fmt.Printf(s, args...)
}

func main() {
    wrapper("%s", 42)
}

追蹤

透過新的 runtime/trace 套件的 使用者註解 API,使用者可以記錄執行時間追蹤中的應用程式級別資訊,並建立相關 goroutine 的群組。go tool trace 指令會在時間追蹤檢視和新的使用者任務/區域分析頁面中視覺化這些資訊。

Cgo

自 Go 1.10 以來,cgo 已將一些 C 指標類型轉換為 Go 型別 uintptr。這些類型包括 Darwin 的 CoreFoundation 架構中的 CFTypeRef 層級和 Java JNI 介面中的 jobject 層級。在 Go 1.11 中,已經對偵測這些類型的程式碼進行若干項改善。使用這些類型的程式碼可能需要進行一些更新。詳情請參閱 Go 1.10 注意事項

Go 指令

環境變數 GOFLAGS 現在可用於設定 go 指令的預設旗標。這在特定狀況下很有用。連結因為 DWARF 而在效能不佳的系統上可能會明顯變慢,使用者可能希望預設設定為 -ldflags=-w。對於模組,某些使用者和 CI 系統會希望總是使用供應商,因此他們應該預設設定為 -mod=vendor。如需更多資訊,請參閱 go 指令文件

Godoc

Go 1.11 將會是最後一個支援 godoc 的命令列介面的版本。在未來的版本中,godoc 將只會是網路伺服器。使用者應該使用 go doc 來代替命令列的說明輸出。

godoc 網路伺服器現在會顯示新增 API 功能的 Go 版本。型別、函式和方法的初始 Go 版本會右對齊顯示。例如,請參閱 UserCacheDir,右側顯示「1.11」。對於結構體欄位,當結構體欄位是在與型別本身新增時不同的 Go 版本中新增時,會加入內嵌註解。如需結構體欄位的範例,請參閱 ClientTrace.Got1xxResponse

Gofmt

Go 原始碼預設格式設定有一個次要的詳細資訊已變更。當格式設定有內嵌註解的表示式清單時,註解會根據啟發式方法對齊。不過,在某些狀況下,對齊會太容易分成多行,或產生過多空白。啟發式方法已經變更,以提供寫作人類可讀程式碼更好的行為。

請注意隨著時間經過,這些對 gofmt 的次要更新會持續進行。一般而言,需要持續格式設定 Go 原始碼的一致性的系統應該使用特定版本 gofmt 二進位檔。如需更多資訊,請參閱 go/format 套件文件。

執行

go run 指令現在允許單一匯入路徑、目錄名稱或相符單一套件的樣式。這允許使用 go run pkggo run dir,最重要的部分是 go run .

執行環境

執行時期現在使用分散式堆疊佈局,因此 Go 堆疊大小不再有任何限制(之前限制為 512GiB)。這也修正了混合 Go/C 二進位檔或使用 -race 編譯二進位檔中罕見的「位址空間衝突」失敗情況。

在 macOS 和 iOS 上,執行時期現在使用 libSystem.dylib,而非直接呼叫核心。這應使 Go 二進位檔與未來版本的 macOS 和 iOS 相容性較高。syscall 套件仍然直接進行系統呼叫;計畫於未來版本修正這個部分。

效能

和往常一樣,變更如此一般化且多樣,難以做出有關效能的精確論述。由於核心函式庫中進階的生成程式碼和最佳化,大多數程式應執行得快速一點。

math/big 套件已進行多項效能變更,以及多項針對特定於 GOARCH=arm64 的樹狀變更。

編譯器工具鏈

編譯器現在最佳化表單格式的地圖清除作業:

for k := range m {
    delete(m, k)
}

編譯器現在最佳化表單格式的分片延伸:append(s, make([]T, n)...)

編譯器現在執行更進階的邊界檢查和分支消除。值得注意的是,編譯器現在辨識傳遞關係,因此如果 i<jj<len(s),編譯器便能使用這些事實消除 s[i] 的邊界檢查。它也了解簡單的算術,例如 s[i-10],且能在迴圈中辨識更多歸納案例。此外,編譯器現在使用邊界資訊更進階地最佳化移位運算。

標準函式庫

標準函式庫的所有變更都為次要變更。

函式庫的次要變更

和往常一樣,有許多次要的函式庫變更和更新,考量到了 Go 1 相容性承諾

crypto

某些密碼運算,包括 ecdsa.Signrsa.EncryptPKCS1v15rsa.GenerateKey,現在會隨機讀取額外的隨機位元組,以確保測試不依賴於內部行為。

crypto/cipher

新的函式 NewGCMWithTagSize 實作了具有非標準標籤長度的伽洛瓦計數模式,以與現有的密碼系統相容。

crypto/rsa

PublicKey 現在實作了 Size 方法,回傳模數大小(單位為位元組)。

crypto/tls

ConnectionState 的新 ExportKeyingMaterial 方法允許根據 RFC 5705 匯出連結到連線的密鑰材料。

crypto/x509

不再遵循過時的舊行為,即當不存在主旨備用名稱時,將 CommonName 欄位視為主機名稱,現在會在 CN 不是有效主機名稱時停用此行為。可以藉由將試驗性質的值 x509ignoreCN=1 加入 GODEBUG 環境變數來完全略過 CommonName 。略過 CN 時,沒有 SAN 的憑證會在具有名稱限制的鏈下進行驗證,而不是傳回 NameConstraintsWithoutSANs

現在再次查看擴充金鑰使用限制,僅當它們出現在 KeyUsages 欄位中時才檢查,而不是總是檢查。VerifyOptions 的行為與 Go 1.9 及更早版本相符。

SystemCertPool 傳回的值現在已快取,可能不會反映呼叫之間的系統變更。

debug/elf

新增多個 ELFOSABIEM 常數。

encoding/asn1

MarshalUnmarshal 現在支援欄位的「私人」類別註解。

encoding/base32

針對不完整區塊,解碼器現在會一致傳回 io.ErrUnexpectedEOF。在某些情況下,它以前會傳回 io.EOF

encoding/csv

Reader 現在會拒絕嘗試將 Comma 欄位設定為雙引號字元,因為雙引號字元在 CSV 中已有特殊意義。

html/template

當有型介面值傳遞至隱含的轉譯函數時,套件已經改變其行為。以前此類值寫為 <nil>(轉譯過的格式)。現在這些值會遭到忽略,就像未有型的 nil 值會被忽略(而且一直都是這樣)。

image/gif

現在支援非循環的動畫 GIF。它們標示為 LoopCount 為 -1。

io/ioutil

TempFile 函數現在支援指定隨機字元放置在檔案名稱中的位置。如果 prefix 參數包含「*」,隨機字串會取代「*」。例如,prefix 參數為「myname.*.bat」會產生亂數檔名,例如「myname.123456.bat」。如果沒有包含「*」,則會保留舊行為,而隨機數位會附加到尾端。

math/big

ModInverse 現在會在 g 和 n 不是互質時傳回 nil。結果以前未定義。

mime/multipart

缺少/空的檔案名稱所產生的表單資料處置,已還原至 Go 1.9 中的行為:針對表單資料部分,表單中值會在 Value 欄位,而非 File 欄位中。在 Go 版本 1.10 至 1.10.3 中,表單資料部分有缺少/空的檔案名稱和非空的「Content-Type」欄位,則儲存在 File 欄位。此變更在 1.10 中是錯誤的,已還原至 1.9 行為。

mime/quotedprintable

為了支援在野外發現的無效輸入,此套件現容許非 ASCII 位元組,但不會驗證它們的編碼。

net

新型 ListenConfig 類型和新型 Dialer.Control 欄位允許在分別接受和建立連線之前設定通訊座選項。

syscall.RawConnReadWrite 方法現在在 Windows 上可以正確運作。

net 套件現在會在於 TCPConn.ReadFrom 中的 TCP 連線間複製資料時自動使用 splice 系統呼叫程式(由 io.Copy 呼叫)。結果是更快速、更有效率的 TCP 代理。

TCPConn.FileUDPConn.FileUnixConn.FileIPConn.File 方法不再將回傳的 *os.File 放到封鎖模式。

net/http

Transport 類型有新的 MaxConnsPerHost 選項,允許限制每個主機的最大連線數量。

Cookie 類型有新的 SameSite 欄位(一種新類型的 SameSite)來表示 Cookies 的新屬性,最近已受到大部分瀏覽器的支援。net/httpTransport 沒有使用 SameSite 屬性,但此套件支援剖析和序列化該屬性供瀏覽器使用。

在呼叫 ShutdownClose 後,不再允許重複使用 Server。在過去,此舉從未正式被支援過,而且經常產生令人驚訝的行為。現在,在停用或關閉之後,對伺服器的 Serve 方法所有未來的呼叫都會傳回錯誤。

已針對 HTTP 狀態碼 421 定義常數 StatusMisdirectedRequest

HTTP 伺服器在收到分段式 HTTP/1.1 請求後,不會再取消內容或傳送至 CloseNotifier 通道。瀏覽器不會使用 HTTP 分段傳輸,但有些客戶端(例如 Debian 的 apt)可能會設定為這樣做。

DefaultTransport 使用的 ProxyFromEnvironment 現在支援 NO_PROXY 環境變數中的 CIDR 符號和通訊埠。

net/http/httputil

ReverseProxy 新增 ErrorHandler 選項,允許變更錯誤處理方式。

ReverseProxy 現在也會將「TE: trailers」請求標頭傳遞給後端,這是 gRPC 協定的規定。

os

新增的 UserCacheDir 函式會傳回使用者特定快取資料的預設根目錄。

新增的 ModeIrregularFileMode 位元,表示檔案並非一般檔案,但也沒有其他已知資訊,或者它不是連接埠、裝置、命名管線、符號鏈結,或其他 Go 已定義模式位元的檔案類型。

Symlink 現在可在啟動開發人員模式的機器上讓 Windows 10 的非特權使用者使用。

當將非封鎖描述子傳遞給 NewFile 時,所得的 *File 會維持在非封鎖模式。這表示對該 *File 的 I/O 會使用執行時期輪詢器,而不是獨立執行緒,而且 SetDeadline 方法會起作用。

os/signal

新的 Ignored 函式會報告訊號目前是否遭到忽略。

os/user

os/user 套件現在可以使用建置標籤「osusergo」以純 Go 模式進行建置,且與環境變數 CGO_ENABLED=0 之使用無關。以前,使用套件的純 Go 實作的唯一方法是在整個程式中停用 cgo 支援。

runtime

設定 GODEBUG=tracebackancestors=N 環境變數後,偵錯追蹤現在會加入 goroutines 建立堆疊,其中 N 限制要報告的祖先 goroutines 數量。

runtime/pprof

此版本新增「allocs」設定檔類型,會設定自程式開始執行以來分配的位元組總數(包含垃圾回收的位元組)。這與先前以 -alloc_space 模式檢視的「heap」設定檔相同。現在 go test -memprofile=... 會報告「allocs」設定檔,而不是「heap」設定檔。

sync

互斥鎖設定檔現在包含 RWMutex 的讀取器/寫入器競爭。互斥鎖設定檔先前已包含寫入器/寫入器競爭。

syscall

在 Windows 上,幾個欄位已從 uintptr 變更為新的 Pointer 型別,以避免 Go 垃圾收集器問題。同一個變更也套用到 golang.org/x/sys/windows 套件。對於任何受影響的程式碼,使用者應先從 syscall 套件遷移到 golang.org/x/sys/windows 套件,然後在遵循 unsafe.Pointer 轉換規則 的同時,變更為使用 Pointer

在 Linux 上,Faccessatflags 參數現在實作得和 glibc 中的一樣。在較早的 Go 版本中,會忽略 flags 參數。

在 Linux 上,Fchmodatflags 參數現在已經驗證。Linux 的 fchmodat 不支援 flags 參數,因此我們現在模擬 glibc 的行為,如果它不是零,則回傳錯誤。

text/scanner

現在的 Scanner.Scan 方法會傳回 RawString 權杖,而非原始字串字面值的 String

text/template

現在允許透過指派,經由 = 權杖變更範本變數。

  {{ $v := "init" }}
  {{ if true }}
    {{ $v = "changed" }}
  {{ end }}
  v: {{ $v }} {{/* "changed" */}}

在之前的版本中,傳遞給範本函式的非鍵入 nil 值會被忽略。它們現在會當作一般引數傳遞。

time

現在支援時區名稱解析,該名稱由符號和偏移組成。在之前的版本中,數值時區名稱(例如 +03)不被視為有效,當預期時區名稱時,只接受三個字母的縮寫(例如 MST)。