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-shared
和 c-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 套件的資訊,因此它能建立分析工具,讓替代建構系統如 Bazel 和 Buck 能夠同樣順利運作。
建置快取需求
Go 1.11 將是最後支援將環境變數 GOCACHE=off
設為停用 建置快取 的版本(建置快取是在 Go 1.10 中引入)。從 Go 1.12 開始,建置快取將成為必要的步驟,朝著移除 $GOPATH/pkg
邁進。上文所述的模組和套件載入支援,已經需要啟用建置快取。如果您已停用建置快取以避免遇到問題,請提出問題 報告問題,讓我們了解問題所在。
編譯器工具鏈
更多的函數現在符合內嵌的預設條件,包括呼叫 panic
的函數。
編譯器工具鏈現在支援 行指令 中的欄位資訊。
一個新的封裝匯出資料格式已經介紹。這對最終用戶來說應該是透明的,除了加快大型 Go 專案的建置時間之外。如果真的造成問題,可在建置二進位檔案時,透過傳遞 -gcflags=all=-iexport=false
給 go
工具來關閉它。
編譯器現在會拒絕在類型轉換保護中宣告的未用變數,例如在以下範例的 x
func f(v interface{}) {
switch x := v.(type) {
}
}
這已經遭到 gccgo
和 go/types 拒絕。
組譯器
amd64
的組譯器現在接受 AVX512 指令。
除錯
編譯器現在產生更多明顯的正確除錯資訊,用於最佳化的二進位檔案,包括變數位置資訊、行數和中斷點位置。透過這個方法才能除錯沒有 -N
-l
編譯的二進位檔案。除錯資訊品質仍有其限制,其中有些是基本的,其他則是會持續提升至往後發布的版本中。
DWARF 區段現在是預設壓縮,因為是由編譯器產生的擴充及更準確的除錯資訊。這種方法對大多數 ELF 工具來說是透明的(例如 Linux 和 *BSD 上的除錯器),且受到所有平台上的 Delve 除錯器的支援,但對於 macOS 和 Windows 上的原生工具而言,支援有限。若要停用 DWARF 壓縮,請在建置二進位檔案時,傳遞 -ldflags=-compressdwarf=false
給 go
工具。
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
pkg
或 go
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<j
且 j<len(s)
,編譯器便能使用這些事實消除 s[i]
的邊界檢查。它也了解簡單的算術,例如 s[i-10]
,且能在迴圈中辨識更多歸納案例。此外,編譯器現在使用邊界資訊更進階地最佳化移位運算。
標準函式庫
標準函式庫的所有變更都為次要變更。
函式庫的次要變更
和往常一樣,有許多次要的函式庫變更和更新,考量到了 Go 1 相容性承諾。
crypto
某些密碼運算,包括 ecdsa.Sign
、rsa.EncryptPKCS1v15
和 rsa.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
encoding/asn1
Marshal
和 Unmarshal
現在支援欄位的「私人」類別註解。
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.RawConn
的 Read
和 Write
方法現在在 Windows 上可以正確運作。
net
套件現在會在於 TCPConn.ReadFrom
中的 TCP 連線間複製資料時自動使用 splice
系統呼叫程式(由 io.Copy
呼叫)。結果是更快速、更有效率的 TCP 代理。
TCPConn.File
、UDPConn.File
、UnixConn.File
和 IPConn.File
方法不再將回傳的 *os.File
放到封鎖模式。
net/http
Transport
類型有新的 MaxConnsPerHost
選項,允許限制每個主機的最大連線數量。
Cookie
類型有新的 SameSite
欄位(一種新類型的 SameSite
)來表示 Cookies 的新屬性,最近已受到大部分瀏覽器的支援。net/http
的 Transport
沒有使用 SameSite
屬性,但此套件支援剖析和序列化該屬性供瀏覽器使用。
在呼叫 Shutdown
或 Close
後,不再允許重複使用 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
函式會傳回使用者特定快取資料的預設根目錄。
新增的 ModeIrregular
是 FileMode
位元,表示檔案並非一般檔案,但也沒有其他已知資訊,或者它不是連接埠、裝置、命名管線、符號鏈結,或其他 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 上,Faccessat
的 flags
參數現在實作得和 glibc 中的一樣。在較早的 Go 版本中,會忽略 flags
參數。
在 Linux 上,Fchmodat
的 flags
參數現在已經驗證。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
)。