Go 1.12 發行說明
Go 1.12 簡介
最新的 Go 版本 1.12 在 Go 1.11 釋出六個月後推出。它的主要變化在於工具鏈、執行時和庫的實現。與以往一樣,此版本保持了 Go 1 的相容性承諾。我們預計幾乎所有 Go 程式都能像以前一樣繼續編譯和執行。
語言變化
語言規範沒有變化。
移植
競態檢測器現在支援 linux/arm64。
Go 1.12 是支援 FreeBSD 10.x 的最後一個版本,該版本已達到生命週期結束。Go 1.13 將需要 FreeBSD 11.2+ 或 FreeBSD 12.0+。FreeBSD 12.0+ 需要一個設定了 COMPAT_FREEBSD11 選項的核心(這是預設設定)。
cgo 現在支援 linux/ppc64。
hurd 現在是 GOOS 的一個識別值,保留用於 GNU/Hurd 系統,與 gccgo 配合使用。
Windows
Go 的新 windows/arm 埠支援在樹莓派 3 等 32 位 ARM 晶片上的 Windows 10 IoT Core 上執行 Go。
AIX
Go 現在支援 POWER8 架構上的 AIX 7.2 及更高版本 (aix/ppc64)。外部連結、cgo、pprof 和競態檢測器尚未支援。
Darwin
Go 1.12 是將在 macOS 10.10 Yosemite 上執行的最後一個版本。Go 1.13 將需要 macOS 10.11 El Capitan 或更高版本。
在 Darwin 上進行系統呼叫時,現在使用 libSystem,確保與未來版本的 macOS 和 iOS 的向前相容性。切換到 libSystem 觸發了對私有 API 使用的額外 App Store 檢查。由於它被視為私有,syscall.Getdirentries 現在在 iOS 上總是以 ENOSYS 失敗。此外,syscall.Setrlimit 在以前成功的某些地方報告 invalid argument。這些後果並非 Go 特有,使用者應期望與 libSystem 的實現保持行為一致。
工具
go tool vet 不再支援
go vet 命令已被重寫,作為一系列不同原始碼分析工具的基礎。有關詳細資訊,請參閱 golang.org/x/tools/go/analysis 包。其副作用是 go tool vet 不再受支援。使用 go tool vet 的外部工具必須更改為使用 go vet。使用 go vet 而不是 go tool vet 應該適用於所有受支援的 Go 版本。
作為此更改的一部分,實驗性的 -shadow 選項不再與 go vet 一起使用。現在可以使用以下命令檢查變數遮蔽:
go get -u golang.org/x/tools/go/analysis/passes/shadow/cmd/shadow
go vet -vettool=$(which shadow)
教程
Go 教程不再包含在主二進位制分發中。要在本地執行教程,請手動安裝它,而不是執行 go tool tour
go get -u golang.org/x/tour
tour
構建快取要求
構建快取現在是消除 $GOPATH/pkg 的一步。設定環境變數 GOCACHE=off 將導致寫入快取的 go 命令失敗。
僅限二進位制包
Go 1.12 是最後一個支援僅限二進位制包的版本。
Cgo
Go 1.12 會將 C 型別 EGLDisplay 轉換為 Go 型別 uintptr。此更改類似於 Go 1.10 及更高版本處理 Darwin 的 CoreFoundation 和 Java 的 JNI 型別的方式。有關更多資訊,請參閱 cgo 文件。
使用 Cgo 的包中不再接受被修改的 C 名稱。請改用 Cgo 名稱。例如,使用文件化的 cgo 名稱 C.char,而不是 cgo 生成的被修改名稱 _Ctype_char。
模組
當 GO111MODULE 設定為 on 時,go 命令現在支援在模組目錄之外進行模組感知操作,前提是這些操作不需要解析相對於當前目錄的匯入路徑或顯式編輯 go.mod 檔案。諸如 go get、go list 和 go mod download 等命令的行為就像在一個初始為空的模組中一樣。在此模式下,go env GOMOD 報告系統的空裝置(/dev/null 或 NUL)。
下載和提取模組的 go 命令現在可以安全地併發呼叫。模組快取 (GOPATH/pkg/mod) 必須位於支援檔案鎖定的檔案系統中。
go.mod 檔案中的 go 指令現在指示該模組中檔案使用的語言版本。如果不存在現有版本,它將設定為當前版本 (go 1.12)。如果模組的 go 指令指定了比正在使用的工具鏈更新的版本,go 命令將嘗試構建包,並且只有在構建失敗時才會指出不匹配。
go 指令的這種更改意味著,如果您使用 Go 1.12 構建一個模組,從而在 go.mod 檔案中記錄 go 1.12,那麼在嘗試使用 Go 1.11 到 Go 1.11.3 構建同一模組時將收到錯誤。Go 1.11.4 或更高版本將正常工作,早於 Go 1.11 的版本也將正常工作。如果您必須使用 Go 1.11 到 1.11.3,您可以透過使用 Go 1.12 go 工具,透過 go mod edit -go=1.11 將語言版本設定為 1.11 來避免此問題。
當無法使用活動模組解析匯入時,go 命令現在將嘗試使用主模組的 replace 指令中提到的模組,然後再查詢模組快取和通常的網路源。如果找到匹配的替換但 replace 指令未指定版本,則 go 命令使用派生自零 time.Time 的偽版本(例如 v0.0.0-00010101000000-000000000000)。
編譯器工具鏈
編譯器的活躍變數分析已改進。這可能意味著在此版本中,終結器將比以前的版本更早執行。如果這是一個問題,請考慮適當新增 runtime.KeepAlive 呼叫。
現在預設情況下,更多函式(包括只調用另一個函式的函式)有資格進行內聯。這種額外的內聯使得使用 runtime.CallersFrames 而不是直接迭代 runtime.Callers 的結果變得更加重要。
// Old code which no longer works correctly (it will miss inlined call frames).
var pcs [10]uintptr
n := runtime.Callers(1, pcs[:])
for _, pc := range pcs[:n] {
f := runtime.FuncForPC(pc)
if f != nil {
fmt.Println(f.Name())
}
}
// New code which will work correctly.
var pcs [10]uintptr
n := runtime.Callers(1, pcs[:])
frames := runtime.CallersFrames(pcs[:n])
for {
frame, more := frames.Next()
fmt.Println(frame.Function)
if !more {
break
}
}
由編譯器生成的用於實現方法表示式的包裝器不再由 runtime.CallersFrames 和 runtime.Stack 報告。它們也不會在 panic 堆疊跟蹤中列印。此更改使 gc 工具鏈與 gccgo 工具鏈保持一致,後者已從堆疊跟蹤中省略了此類包裝器。這些 API 的客戶端可能需要調整以適應缺失的幀。對於必須在 1.11 和 1.12 版本之間互操作的程式碼,可以將方法表示式 x.M 替換為函式字面量 func (...) { x.M(...) } 。
編譯器現在接受 -lang 標誌來設定要使用的 Go 語言版本。例如,-lang=go1.8 會導致編譯器在程式使用類型別名(Go 1.9 中新增)時發出錯誤。在 Go 1.12 之前進行的語言更改未始終強制執行。
編譯器工具鏈現在使用不同的約定來呼叫 Go 函式和彙編函式。這對於使用者來說應該是不可見的,除了同時跨越 Go 和彙編以及跨越包邊界的呼叫。如果連結導致“relocation target not defined for ABIInternal (but is defined for ABI0)”之類的錯誤,請參閱 ABI 設計文件的相容性部分。
編譯器生成的 DWARF 除錯資訊有許多改進,包括引數列印和變數位置資訊的改進。
Go 程式現在還在 linux/arm64 上維護堆疊幀指標,以利於 perf 等分析工具。幀指標維護會產生少量執行時開銷,開銷因情況而異,但平均約為 3%。要構建不使用幀指標的工具鏈,請在執行 make.bash 時設定 GOEXPERIMENT=noframepointer。
過時的“安全”編譯器模式(由 -u gcflag 啟用)已刪除。
godoc 和 go doc
在 Go 1.12 中,godoc 不再具有命令列介面,而僅是一個 Web 伺服器。使用者應該使用 go doc 獲取命令列幫助輸出。Go 1.12 是最後一個包含 godoc Web 伺服器的版本;在 Go 1.13 中,它將透過 go get 提供。
go doc 現在支援 -all 標誌,它將列印所有匯出的 API 及其文件,就像以前的 godoc 命令列一樣。
go doc 現在還包含 -src 標誌,它將顯示目標的原始碼。
Trace
跟蹤工具現在支援繪製變異器利用率曲線,包括對執行跟蹤的交叉引用。這些對於分析垃圾收集器對應用程式延遲和吞吐量的影響非常有用。
彙編器
在 arm64 上,平臺暫存器從 R18 重新命名為 R18_PLATFORM,以防止意外使用,因為作業系統可以選擇保留此暫存器。
執行時
當堆的大部分仍然存活時,Go 1.12 顯著提高了清掃效能。這減少了垃圾收集後立即的分配延遲。
Go 執行時現在更積極地將記憶體釋放回作業系統,特別是在無法重用現有堆空間的大量分配之後。
Go 執行時的計時器和截止時間程式碼更快,並且在 CPU 數量更多時擴充套件性更好。特別是,這提高了操縱網路連線截止時間的效能。
在 Linux 上,執行時現在使用 MADV_FREE 釋放未使用的記憶體。這更有效率,但可能導致報告的 RSS 更高。核心將在需要時回收未使用的資料。要恢復到 Go 1.11 的行為 (MADV_DONTNEED),請設定環境變數 GODEBUG=madvdontneed=1。
將 cpu.extension=off 新增到 GODEBUG 環境變數現在會停用標準庫和執行時中可選 CPU 指令集擴充套件的使用。這在 Windows 上尚不支援。
Go 1.12 透過修復大量堆分配的過度計數,提高了記憶體配置檔案的準確性。
堆疊回溯、runtime.Caller 和 runtime.Callers 不再包含編譯器生成的初始化函式。在全域性變數初始化期間進行堆疊回溯現在將顯示一個名為 PKG.init.ializers 的函式。
標準庫
TLS 1.3
Go 1.12 在 crypto/tls 包中添加了可選的 TLS 1.3 支援,具體由 RFC 8446 指定。可以透過將值 tls13=1 新增到 GODEBUG 環境變數來啟用它。它將在 Go 1.13 中預設啟用。
要協商 TLS 1.3,請確保您沒有在 Config 中設定顯式 MaxVersion,並使用環境變數 GODEBUG=tls13=1 執行您的程式。
除了 ConnectionState 中的 TLSUnique 和重新協商之外,所有 TLS 1.2 功能在 TLS 1.3 中都可用,並提供等效或更好的安全性和效能。請注意,儘管 TLS 1.3 向後相容以前的版本,但某些舊系統在嘗試協商它時可能無法正常工作。過小而不安全的 RSA 證書金鑰(包括 512 位金鑰)將無法與 TLS 1.3 配合使用。
TLS 1.3 密碼套件不可配置。所有支援的密碼套件都是安全的,如果在 Config 中設定了 PreferServerCipherSuites,則偏好順序基於可用的硬體。
目前不支援作為客戶端或伺服器的早期資料(也稱為“0-RTT 模式”)。此外,Go 1.12 伺服器不支援在客戶端傳送意外早期資料時跳過。由於 TLS 1.3 0-RTT 模式涉及客戶端保留有關哪些伺服器支援 0-RTT 的狀態,Go 1.12 伺服器不能成為負載均衡池的一部分,其中一些其他伺服器確實支援 0-RTT。如果將域從支援 0-RTT 的伺服器切換到 Go 1.12 伺服器,則必須在切換之前至少在頒發的會話票證的生命週期內停用 0-RTT,以確保不間斷執行。
在 TLS 1.3 中,客戶端是握手中最後發言的一方,因此如果它導致伺服器上發生錯誤,該錯誤將由第一次 Read 在客戶端上返回,而不是由 Handshake 返回。例如,如果伺服器拒絕客戶端證書,就會出現這種情況。同樣,會話票證現在是握手後訊息,因此只有在客戶端第一次 Read 時才會收到。
對庫的微小更改
與往常一樣,庫中有各種微小的更改和更新,這些都是在遵守 Go 1 相容性承諾的前提下進行的。
bufio
如果 Peek 之後呼叫 Reader 的 UnreadRune 和 UnreadByte 方法,它們現在將返回錯誤。
bytes
新函式 ReplaceAll 返回一個位元組切片的副本,其中所有非重疊的值例項都被另一個值替換。
零值 Reader 的指標現在在功能上等同於 NewReader(nil)。在 Go 1.12 之前,前者在所有情況下都不能替代後者。
crypto/rand
當 Reader.Read 首次阻塞超過 60 秒等待從核心讀取熵時,將列印警告到標準錯誤。
在 FreeBSD 上,Reader 現在使用 getrandom 系統呼叫(如果可用),否則使用 /dev/urandom。
crypto/rc4
此版本刪除了彙編實現,只留下純 Go 版本。Go 編譯器生成的程式碼略好或略差,具體取決於 CPU。RC4 不安全,應僅用於與舊系統相容。
crypto/tls
如果客戶端傳送的初始訊息看起來不像 TLS,伺服器將不再回復警報,並且它將在 RecordHeaderError 的新欄位 Conn 中公開底層 net.Conn。
database/sql
現在可以透過將 *Rows 值傳遞給 Row.Scan 方法來獲取查詢遊標。
expvar
fmt
現在以按鍵排序的順序列印對映,以方便測試。排序規則如下:
- 如果適用,nil 比較為低
- 整數、浮點數和字串按 < 排序
- NaN 小於非 NaN 浮點數
- 布林值 false 在 true 之前
- 複數先比較實部,再比較虛部
- 指標按機器地址比較
- 通道值按機器地址比較
- 結構體依次比較每個欄位
- 陣列依次比較每個元素
- 介面值首先根據描述具體型別的
reflect.Type進行比較,然後根據前面規則描述的具體值進行比較。
列印對映時,非自反鍵值(如 NaN)以前顯示為 <nil>。從這個版本開始,會列印正確的值。
go/doc
為了解決 cmd/doc 中的一些懸而未決的問題,此包有一個新的 Mode 位 PreserveAST,它控制是否清除 AST 資料。
go/token
File 型別有一個新的 LineStart 欄位,它返回給定行的起始位置。這在偶爾處理非 Go 檔案(例如彙編)但希望使用 token.Pos 機制識別檔案位置的程式中特別有用。
影像
RegisterFormat 函式現在可以安全地併發使用。
image/png
顏色少於 16 種的調色盤影像現在編碼為更小的輸出。
io
新的 StringWriter 介面包裝了 WriteString 函式。
math
函式 Sin、Cos、Tan 和 Sincos 現在對巨大的引數應用 Payne-Hanek 範圍縮減。這會產生更準確的結果,但它們不會與早期版本的結果逐位相同。
math/bits
新的擴充套件精度操作 Add、Sub、Mul 和 Div 可用於 uint、uint32 和 uint64 版本。
net
Dialer.DualStack 設定現在被忽略並已棄用;RFC 6555 快速回退(“Happy Eyeballs”)現在預設啟用。要停用,請將 Dialer.FallbackDelay 設定為負值。
同樣,如果 Dialer.KeepAlive 為零,TCP 保活現在預設啟用。要停用,請將其設定為負值。
在 Linux 上,當從 UnixConn 複製到 TCPConn 時,現在使用 splice 系統呼叫。
net/http
HTTP 伺服器現在會以純文字“400 Bad Request”響應拒絕傳送到 HTTPS 伺服器的誤導性 HTTP 請求。
新的 Client.CloseIdleConnections 方法會呼叫 Client 底層 Transport 的 CloseIdleConnections(如果存在)。
Transport 不再拒絕宣告 HTTP Trailers 但不使用分塊編碼的 HTTP 響應。相反,宣告的 Trailers 現在只是被忽略。
Transport 不再像 Go 1.10 和 Go 1.11 那樣嚴格處理 HTTP/2 伺服器 advertised 的 MAX_CONCURRENT_STREAMS 值。預設行為現在恢復到 Go 1.9 的方式:與伺服器的每個連線最多可以有 MAX_CONCURRENT_STREAMS 個活動請求,然後根據需要建立新的 TCP 連線。在 Go 1.10 和 Go 1.11 中,http2 包會阻塞並等待請求完成,而不是建立新連線。要恢復更嚴格的行為,請直接匯入 golang.org/x/net/http2 包並設定 Transport.StrictMaxConcurrentStreams 為 true。
net/url
Parse、ParseRequestURI 和 URL.Parse 現在對包含 ASCII 控制字元(包括 NULL、製表符和換行符)的 URL 返回錯誤。
net/http/httputil
新的 ReverseProxy 現在會自動代理 WebSocket 請求。
os
新的 ProcessState.ExitCode 方法返回程序的退出程式碼。
ModeCharDevice 已新增到 ModeType 位掩碼中,允許在用 ModeType 掩碼 FileMode 時恢復 ModeDevice | ModeCharDevice。
新函式 UserHomeDir 返回當前使用者的主目錄。
RemoveAll 現在支援大多數 Unix 系統上長度超過 4096 個字元的路徑。
File.Sync 現在在 macOS 上使用 F_FULLFSYNC 來正確地將檔案內容重新整理到永久儲存。這可能會導致該方法執行速度比以前的版本慢。
File 現在支援 SyscallConn 方法,該方法返回 syscall.RawConn 介面值。這可用於對底層檔案描述符呼叫系統特定操作。
path/filepath
IsAbs 函式現在在傳遞 Windows 上的保留檔名(例如 NUL)時返回 true。保留名稱列表。
reflect
新的 MapIter 型別是用於遍歷對映的迭代器。此型別透過 Value 型別的新 MapRange 方法公開。它遵循與 range 語句相同的迭代語義,使用 Next 前進迭代器,以及 Key/Value 訪問每個條目。
regexp
Copy 不再是避免鎖競爭所必需的,因此它被部分棄用註釋。如果使用 Copy 的原因是製作具有不同 Longest 設定的兩個副本,那麼它仍然可能是合適的。
runtime/debug
新的 BuildInfo 型別公開了從正在執行的二進位制檔案讀取的構建資訊,僅適用於使用模組支援構建的二進位制檔案。這包括主包路徑、主模組資訊和模組依賴項。此型別透過 BuildInfo 上的 ReadBuildInfo 函式提供。
strings
新函式 ReplaceAll 返回一個字串的副本,其中所有非重疊的值例項都被另一個值替換。
零值 Reader 的指標現在在功能上等同於 NewReader(nil)。在 Go 1.12 之前,前者在所有情況下都不能替代後者。
新的 Builder.Cap 方法返回構建器底層位元組切片的容量。
字元對映函式 Map、Title、ToLower、ToLowerSpecial、ToTitle、ToTitleSpecial、ToUpper 和 ToUpperSpecial 現在始終保證返回有效的 UTF-8。在早期版本中,如果輸入是無效的 UTF-8 但無需應用字元替換,這些例程會錯誤地返回未修改的無效 UTF-8。
syscall
FreeBSD 12 現在支援 64 位 inode。一些型別已相應調整。
現在支援相容版本的 Windows 上的 Unix 套接字(AF_UNIX)地址族。
Windows 上引入了新函式 Syscall18,允許最多 18 個引數的呼叫。
syscall/js
Callback 型別和 NewCallback 函式已重新命名;它們現在分別稱為 Func 和 FuncOf。這是一個破壞性更改,但 WebAssembly 支援仍處於實驗階段,尚未受 Go 1 相容性承諾的約束。任何使用舊名稱的程式碼都需要更新。
如果某個型別實現了新的 Wrapper 介面,ValueOf 將使用它返回該型別的 JavaScript 值。
零 Value 的含義已更改。它現在表示 JavaScript 的 undefined 值,而不是數字零。這是一個破壞性更改,但 WebAssembly 支援仍處於實驗階段,尚未受 Go 1 相容性承諾的約束。任何依賴零 Value 意味著數字零的程式碼都需要更新。
新的 Value.Truthy 方法報告給定值的 JavaScript“真值”。
testing
-benchtime 標誌現在支援設定顯式迭代計數,而不是時間,當值以“x”結尾時。例如,-benchtime=100x 執行基準測試 100 次。
text/template
執行模板時,錯誤中不再截斷長上下文值。
正在執行 "tmpl" at <.very.deep.context.v...>: 對映中沒有 "notpresent" 的條目
現在是
正在執行 "tmpl" at <.very.deep.context.value.notpresent>: 對映中沒有 "notpresent" 的條目
如果模板呼叫的使用者定義函式發生 panic,該 panic 現在會被 Execute 或 ExecuteTemplate 方法捕獲並作為錯誤返回。
time
$GOROOT/lib/time/zoneinfo.zip 中的時區資料庫已更新到版本 2018i。請注意,此 ZIP 檔案僅在作業系統未提供時區資料庫時使用。
unsafe
將 nil unsafe.Pointer 轉換為 uintptr 並透過算術轉換回來是無效的。(這已經無效,但現在會導致編譯器行為異常。)