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 程式碼是透明的,但使用未受 GOARM 保護的浮點指令的 ARM 彙編程式碼將會中斷,必須移植到新介面。
ARMv7 上的 Go 1.11 不再需要配置了 KUSER_HELPERS 的 Linux 核心。此設定在預設核心配置中啟用,但在精簡配置中有時會被停用。
WebAssembly
Go 1.11 增加了一個實驗性的 WebAssembly (js/wasm) 移植。
Go 程式目前編譯成一個 WebAssembly 模組,該模組包含了用於 goroutine 排程、垃圾回收、map 等功能的 Go 執行時。因此,生成的檔案大小至少約為 2 MB,壓縮後為 500 KB。Go 程式可以使用新的實驗性 syscall/js 包呼叫 JavaScript。二進位制檔案大小和與其他語言的互操作性尚未成為優先事項,但可能會在未來的版本中解決。
由於新增了 GOOS 值“js”和 GOARCH 值“wasm”,現在名為 *_js.go 或 *_wasm.go 的 Go 檔案將被 Go 工具忽略,除非正在使用這些 GOOS/GOARCH 值。如果您有符合這些模式的現有檔名,則需要重新命名它們。
更多資訊可以在 WebAssembly wiki 頁面上找到。
RISC-V GOARCH 值已保留
主 Go 編譯器尚不支援 RISC-V 架構但我們已經保留了 GOARCH 值“riscv”和“riscv64”,這些值由支援 RISC-V 的 Gccgo 使用。這意味著名為 *_riscv.go 的 Go 檔案現在也將被 Go 工具忽略,除非正在使用這些 GOOS/GOARCH 值。
工具
模組、包版本控制和依賴管理
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 專案的構建時間。如果它確實引起問題,可以透過在構建二進位制檔案時向 go 工具傳遞 -gcflags=all=-iexport=false 來再次關閉它。
編譯器現在會拒絕在型別 switch 守衛中宣告的未使用變數,例如下面例子中的 x
func f(v interface{}) {
switch x := v.(type) {
}
}
這已經被 gccgo 和 go/types 拒絕。
彙編器
amd64 的彙編器現在接受 AVX512 指令。
除錯
編譯器現在為最佳化後的二進位制檔案生成更精確的除錯資訊,包括變數位置資訊、行號和斷點位置。這應該使得在沒有使用 -N -l 編譯的二進位制檔案上進行除錯成為可能。除錯資訊的質量仍然存在限制,其中一些是根本性的,另一些將隨著未來版本繼續改進。
由於編譯器生成了擴充套件且更準確的除錯資訊,DWARF 部分現在預設被壓縮。這對大多數 ELF 工具(如 Linux 和 *BSD 上的偵錯程式)是透明的,並且在所有平臺上都得到 Delve 偵錯程式的支援,但在 macOS 和 Windows 的原生工具中支援有限。要停用 DWARF 壓縮,請在構建二進位制檔案時向 go 工具傳遞 -ldflags=-compressdwarf=false。
Go 1.11 增加了在偵錯程式內呼叫 Go 函式的實驗性支援。例如,這在斷點暫停時呼叫 String 方法非常有用。目前這僅受 Delve(版本 1.1.0及以上)支援。
Test
自 Go 1.10 起,go test 命令會在被測試的包上執行 go vet,以便在執行測試前識別問題。由於 vet 在執行前使用 go/types 對程式碼進行型別檢查,因此無法透過型別檢查的測試現在會失敗。特別是,在 Go 1.10 中編譯的閉包中包含未使用變數的測試,之前 Go 編譯器錯誤地接受了它們(問題 #3059),但現在會失敗,因為 go/types 在這種情況下會正確報告“未使用變數”錯誤。
go test 的 -memprofile 標誌現在預設為“allocs”配置檔案,它記錄自測試開始以來分配的總位元組數(包括被垃圾回收的位元組)。
Vet
當被分析的包無法透過型別檢查時,go vet 命令現在會報告一個致命錯誤。以前,型別檢查錯誤只會列印一個警告,並使 vet 以狀態碼 1 退出。
此外,go vet 在格式檢查 printf 包裝器時變得更加健壯。Vet 現在能檢測到這個例子中的錯誤
func wrapper(s string, args ...interface{}) {
fmt.Printf(s, args...)
}
func main() {
wrapper("%s", 42)
}
Trace
透過新的 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 系統總是希望使用 vendoring,所以他們應該預設設定 -mod=vendor。更多資訊,請參閱 go 命令文件。
Godoc
Go 1.11 將是最後一個支援 godoc 命令列介面的版本。在未來的版本中,godoc 將只作為 Web 伺服器。使用者應改用 go doc 來獲取命令列幫助輸出。
godoc Web 伺服器現在顯示引入新 API 功能的 Go 版本。型別、函式和方法的初始 Go 版本會右對齊顯示。例如,請看 UserCacheDir,右側有“1.11”。對於結構體欄位,如果該欄位是在與型別本身引入時不同的 Go 版本中新增的,則會新增內聯註釋。關於結構體欄位的示例,請看 ClientTrace.Got1xxResponse。
Gofmt
Go 原始碼預設格式的一個小細節發生了變化。在格式化帶有內聯註釋的表示式列表時,註釋會根據一個啟發式規則進行對齊。然而,在某些情況下,對齊很容易被破壞,或者引入過多的空白。這個啟發式規則已經改變,以更好地適應人類編寫的程式碼。
請注意,gofmt 的這類小更新是會不時發生的。通常,需要 Go 原始碼格式一致的系統應使用特定版本的 gofmt 二進位制檔案。更多資訊請參閱 go/format 包文件。
Run
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 的許多更改。
編譯器工具鏈
編譯器現在優化了以下形式的 map 清除操作
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 實現了帶有非標準標籤長度的伽羅瓦/計數器模式(GCM),以相容現有的加密系統。
crypto/rsa
PublicKey 現在實現了一個 Size 方法,該方法返回模數的大小(以位元組為單位)。
crypto/tls
ConnectionState 的新方法 ExportKeyingMaterial 允許根據 RFC 5705 匯出與連線繫結的金鑰材料。
crypto/x509
當 `CommonName` 欄位不是有效主機名時,在沒有主題備用名稱(SAN)的情況下將其視為 主機名的已棄用舊行為現已被停用。透過將實驗性值 `x509ignoreCN=1` 新增到 `GODEBUG` 環境變數中,可以完全忽略 `CommonName`。當 `CommonName` 被忽略時,沒有 SAN 的證書在帶有名稱約束的鏈下會進行驗證,而不是返回 `NameConstraintsWithoutSANs`。
擴充套件金鑰用法限制現在僅在它們出現在 VerifyOptions 的 KeyUsages 欄位中時才被檢查,而不是總是被檢查。這與 Go 1.9 及更早版本的行為相匹配。
由 SystemCertPool 返回的值現在被快取,並且可能不會反映兩次呼叫之間的系統更改。
debug/elf
encoding/asn1
Marshal 和 Unmarshal 現在支援欄位的“private”類註解。
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
當 g 和 n 不互質時,ModInverse 現在返回 nil。之前的結果是未定義的。
mime/multipart
對缺少/空檔名的表單資料處理已恢復到 Go 1.9 的行為:在表單資料部分的 Form 中,該值在 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 上可以正常工作。
在 Linux 上,net 包現在在 TCPConn.ReadFrom 中(由 io.Copy 呼叫)複製 TCP 連線之間的資料時,會自動使用 splice 系統呼叫。結果是 TCP 代理更快、更高效。
TCPConn.File、UDPConn.File、UnixConn.File 和 IPConn.File 方法不再將返回的 *os.File 設定為阻塞模式。
net/http
Transport 型別有了一個新的 MaxConnsPerHost 選項,允許限制每個主機的最大連線數。
Cookie 型別有了一個新的 SameSite 欄位(新型別也名為 SameSite),用於表示最近大多數瀏覽器支援的新 cookie 屬性。net/http 的 Transport 本身不使用 SameSite 屬性,但該包支援解析和序列化該屬性供瀏覽器使用。
在呼叫 Shutdown 或 Close 後,不再允許重用一個 Server。過去這從未被正式支援,並且常常有令人意外的行為。現在,在關閉或關閉後,所有對伺服器 Serve 方法的未來呼叫都將返回錯誤。
常量 StatusMisdirectedRequest 現在為 HTTP 狀態碼 421 定義。
HTTP 伺服器在接收到管道化的 HTTP/1.1 請求時,將不再取消上下文或在 CloseNotifier 通道上傳送訊號。瀏覽器不使用 HTTP 管道,但某些客戶端(例如 Debian 的 apt)可能配置為使用。
ProxyFromEnvironment,被 DefaultTransport 使用,現在在 NO_PROXY 環境變數中支援 CIDR 表示法和埠。
net/http/httputil
ReverseProxy 有一個新選項 ErrorHandler,允許更改錯誤處理方式。
ReverseProxy 現在也會將 “TE: trailers” 請求頭傳遞給後端,這是 gRPC 協議所要求的。
os
新函式 UserCacheDir 返回用於使用者特定快取資料的預設根目錄。
新的 ModeIrregular 是一個 FileMode 位,用於表示一個檔案不是常規檔案,但對其一無所知,或者它不是套接字、裝置、命名管道、符號連結,或 Go 有定義模式位的其他檔案型別。
在啟用了開發者模式的 Windows 10 機器上,Symlink 現在對非特權使用者也有效。
當一個非阻塞描述符傳遞給 NewFile 時,生成的 *File 將保持在非阻塞模式。這意味著該 *File 的 I/O 將使用執行時輪詢器而不是單獨的執行緒,並且 SetDeadline 方法將起作用。
os/signal
新函式 Ignored 報告一個訊號當前是否被忽略。
os/user
os/user 包現在可以使用構建標籤 “osusergo” 在純 Go 模式下構建,這與是否使用環境變數 CGO_ENABLED=0 無關。以前,使用該包的純 Go 實現的唯一方法是在整個程式中停用 cgo 支援。
runtime
設定 GODEBUG=tracebackancestors=N 環境變數現在會用 goroutine 建立時的堆疊來擴充套件回溯資訊,其中 N 限制了要報告的祖先 goroutine 的數量。
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 包,然後改為使用 Pointer,同時遵守 unsafe.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)在期望時區名稱時被接受。