Go 1.15 發行說明
Go 1.15 簡介
最新的 Go 版本 1.15 釋出於 Go 1.14 六個月之後。其大部分更改都在工具鏈、執行時和庫的實現中。一如既往,此版本保持了 Go 1 的相容性承諾。我們預計幾乎所有 Go 程式都將像以前一樣繼續編譯和執行。
Go 1.15 包括對連結器的重大改進,改善了高核數下小物件的分配,並棄用了X.509 CommonName。GOPROXY 現在支援跳過返回錯誤的代理,並且添加了一個新的嵌入式 tzdata 包。
語言變化
語言沒有變化。
移植
Darwin
正如 Go 1.14 發行說明中宣佈的,Go 1.15 需要 macOS 10.12 Sierra 或更高版本;對以前版本的支援已停止。
正如 Go 1.14 發行說明中宣佈的,Go 1.15 放棄了對 macOS、iOS、iPadOS、watchOS 和 tvOS 上的 32 位二進位制檔案的支援(darwin/386 和 darwin/arm 埠)。Go 繼續支援 64 位 darwin/amd64 和 darwin/arm64 埠。
Windows
當提供了 -buildmode=pie cmd/link 標誌時,Go 現在會生成 Windows ASLR 可執行檔案。Go 命令在 Windows 上預設使用 -buildmode=pie。
-race 和 -msan 標誌現在總是啟用 -d=checkptr,它會檢查 unsafe.Pointer 的使用。以前除了 Windows 之外的所有作業系統都是這樣。
Go 構建的 DLL 不再在收到訊號(例如終端中的 Ctrl-C)時導致程序退出。
安卓
連結 Android 二進位制檔案時,Go 1.15 顯式選擇 NDK 最新版本中可用的 lld 連結器。lld 連結器可以避免某些裝置上的崩潰,並計劃在未來的 NDK 版本中成為預設的 NDK 連結器。
OpenBSD
Go 1.15 添加了對 GOARCH=arm 和 GOARCH=arm64 上 OpenBSD 6.7 的支援。Go 的早期版本已經支援 GOARCH=386 和 GOARCH=amd64 上 OpenBSD 6.7。
RISC-V
在改進 Linux 上 64 位 RISC-V 埠(GOOS=linux,GOARCH=riscv64)的穩定性和效能方面取得了進展。它現在還支援非同步搶佔。
386
Go 1.15 是最後一個支援僅 x87 浮點硬體(GO386=387)的版本。未來的版本將要求 386 上至少支援 SSE2,將 Go 的最低 GOARCH=386 要求提高到 Intel Pentium 4(2000 年釋出)或 AMD Opteron/Athlon 64(2003 年釋出)。
工具
Go 命令
GOPROXY 環境變數現在支援跳過返回錯誤的代理。代理 URL 現在可以用逗號 (,) 或豎線字元 (|) 分隔。如果代理 URL 後跟逗號,則 go 命令只會在 HTTP 響應為 404 或 410 後嘗試列表中的下一個代理。如果代理 URL 後跟豎線字元,則 go 命令會在任何錯誤後嘗試列表中的下一個代理。請注意,GOPROXY 的預設值仍為 https://proxy.golang.org,direct,它在出現錯誤時不會回退到 direct。
go test
更改 -timeout 標誌現在會使快取的測試結果失效。當使用較短的超時重新呼叫 go test 時,使用較長超時執行的測試的快取結果將不再算作透過。
標誌解析
go test 和 go vet 中的各種標誌解析問題已得到修復。值得注意的是,GOFLAGS 中指定的標誌處理得更加一致,並且 -outputdir 標誌現在將相對路徑解釋為相對於 go 命令的工作目錄(而不是每個單獨測試的工作目錄)。
模組快取
模組快取的位置現在可以使用 GOMODCACHE 環境變數設定。GOMODCACHE 的預設值為 GOPATH[0]/pkg/mod,這是此更改之前模組快取的位置。
現在可以使用一種解決方法來解決 go 命令訪問模組快取時出現的 Windows“訪問被拒絕”錯誤,該錯誤由外部程式同時掃描檔案系統引起(請參閱問題 #36568)。預設情況下不啟用該解決方法,因為它在 Go 1.14.2 和 1.13.10 以下版本與同一模組快取同時執行時不安全。可以透過顯式設定環境變數 GODEBUG=modcacheunzipinplace=1 來啟用它。
Vet
string(x) 的新警告
vet 工具現在會警告 string(x) 形式的轉換,其中 x 的整數型別不是 rune 或 byte。Go 的經驗表明,這種形式的許多轉換錯誤地假設 string(x) 求值為整數 x 的字串表示。它實際上求值為包含 x 值 UTF-8 編碼的字串。例如,string(9786) 不求值為字串 "9786";它求值為字串 "\xe2\x98\xba",或 "☺"。
正確使用 string(x) 的程式碼可以重寫為 string(rune(x))。或者,在某些情況下,使用合適的位元組切片 buf 呼叫 utf8.EncodeRune(buf, x) 可能是正確的解決方案。其他程式碼很可能應該使用 strconv.Itoa 或 fmt.Sprint。
使用 go test 時,此新的 vet 檢查預設啟用。
我們正在考慮在 Go 的未來版本中禁止此轉換。也就是說,語言將改變為僅允許 string(x) 用於整數 x,當 x 的型別為 rune 或 byte 時。這種語言更改將不向後相容。我們正在使用此 vet 檢查作為更改語言的第一步。
不可能的介面轉換的新警告
vet 工具現在會警告從一種介面型別到另一種介面型別的型別斷言,當型別斷言總是失敗時。如果兩個介面型別實現一個同名但具有不同型別簽名的方法,就會發生這種情況。
沒有理由編寫總是失敗的型別斷言,因此任何觸發此 vet 檢查的程式碼都應該重寫。
使用 go test 時,此新的 vet 檢查預設啟用。
我們正在考慮在 Go 的未來版本中禁止不可能的介面型別斷言。這種語言更改將不向後相容。我們正在使用此 vet 檢查作為更改語言的第一步。
執行時
如果 panic 呼叫時傳入的值的型別派生自以下任何一種:bool、complex64、complex128、float32、float64、int、int8、int16、int32、int64、string、uint、uint8、uint16、uint32、uint64、uintptr,則將列印該值,而不僅僅是其地址。以前,這僅適用於精確這些型別的值。
在 Unix 系統上,如果使用 kill 命令或 kill 系統呼叫向 Go 程式傳送 SIGSEGV、SIGBUS 或 SIGFPE 訊號,並且如果該訊號未透過 os/signal.Notify 處理,Go 程式現在將可靠地崩潰並帶有堆疊跟蹤。在早期版本中,行為是不可預測的。
在高核數下,小物件的分配現在表現得好得多,並且最壞情況下的延遲更低。
將小整數值轉換為介面值不再導致分配。
在關閉通道上的非阻塞接收現在與在開啟通道上的非阻塞接收一樣好。
編譯器
unsafe 包的安全規則允許在呼叫某些函式時將 unsafe.Pointer 轉換為 uintptr。以前,在某些情況下,編譯器允許多個鏈式轉換(例如,syscall.Syscall(…, uintptr(uintptr(ptr)), …))。編譯器現在要求正好一個轉換。使用多個轉換的程式碼應更新以滿足安全規則。
Go 1.15 透過消除某些型別的 GC 元資料和更積極地消除未使用的型別元資料,將典型二進位制檔案大小比 Go 1.14 減少了約 5%。
工具鏈現在透過將函式對齊到 32 位元組邊界並填充跳轉指令來緩解 GOARCH=amd64 上的 Intel CPU 錯誤 SKX102。雖然這種填充增加了二進位制檔案大小,但這被上面提到的二進位制檔案大小改進所彌補。
Go 1.15 為編譯器和彙編器添加了 -spectre 標誌,以允許啟用 Spectre 緩解措施。這些幾乎從不需要,主要作為“縱深防禦”機制提供。有關詳細資訊,請參閱 Spectre wiki 頁面。
編譯器現在會拒絕與所應用的宣告無關的 //go: 編譯器指令,並報告“ misplaced compiler directive ”錯誤。此類錯誤應用的指令以前是錯誤的,但被編譯器靜默忽略。
編譯器的 -json 最佳化日誌現在報告大型(>= 128 位元組)副本,幷包括逃逸分析決策的解釋。
連結器
此版本包括對 Go 連結器的重大改進,這些改進減少了連結器資源使用(時間和記憶體)並提高了程式碼的健壯性/可維護性。
對於一組具有代表性的大型 Go 程式,在 amd64 架構上執行的基於 ELF 的作業系統(Linux、FreeBSD、NetBSD、OpenBSD、Dragonfly 和 Solaris)上,連結速度平均快 20%,記憶體需求平均減少 30%,對於其他架構/作業系統組合,改進則較為溫和。
連結器效能更好的關鍵因素是重新設計了目標檔案格式,以及重組了內部階段以增加併發性(例如,並行應用重定位到符號)。Go 1.15 中的目標檔案略大於其 1.14 等效檔案。
這些更改是現代化 Go 連結器的多版本專案的一部分,這意味著未來版本中將有更多連結器改進。
連結器現在在 linux/amd64 和 linux/arm64 上,對於 -buildmode=pie 預設為內部連結模式,因此這些配置不再需要 C 連結器。外部連結模式(Go 1.14 中對於 -buildmode=pie 是預設值)仍然可以透過 -ldflags=-linkmode=external 標誌請求。
Objdump
objdump 工具現在支援使用 -gnu 標誌以 GNU 彙編器語法反彙編。
標準庫
新的嵌入式 tzdata 包
Go 1.15 包含一個新包 time/tzdata,它允許將時區資料庫嵌入到程式中。匯入此包(作為 import _ "time/tzdata")允許程式即使在本地系統上沒有時區資料庫也能找到時區資訊。您也可以透過使用 -tags timetzdata 構建來嵌入時區資料庫。這兩種方法都會使程式大小增加約 800 KB。
Cgo
Go 1.15 會將 C 型別 EGLConfig 轉換為 Go 型別 uintptr。此更改類似於 Go 1.12 及更高版本處理 EGLDisplay、Darwin 的 CoreFoundation 和 Java 的 JNI 型別的方式。有關更多資訊,請參閱 cgo 文件。
在 Go 1.15.3 及更高版本中,cgo 將不允許 Go 程式碼在堆疊或堆上分配未定義的結構型別(僅定義為 struct S; 或類似的 C 結構)。Go 程式碼只允許使用指向這些型別的指標。分配此類結構例項並將指標或完整的結構值傳遞給 C 程式碼始終是不安全的,並且不太可能正常工作;現在被禁止。修復方法是重寫 Go 程式碼以僅使用指標,或者透過包含適當的 C 標頭檔案來確保 Go 程式碼看到結構的完整定義。
X.509 CommonName 棄用
當不存在 Subject Alternative Names 時,將 X.509 證書上的 CommonName 欄位視為主機名的已棄用、舊式行為現已預設停用。可以透過將值 x509ignoreCN=0 新增到 GODEBUG 環境變數中來暫時重新啟用它。
請注意,如果 CommonName 是無效的主機名,它總是會被忽略,無論 GODEBUG 設定如何。無效名稱包括那些包含除字母、數字、連字元和下劃線之外的任何字元的名稱,以及那些帶有空標籤或尾隨點的名稱。
對庫的微小更改
與往常一樣,庫中有各種微小的更改和更新,這些都是在遵守 Go 1 相容性承諾的前提下進行的。
bufio
當 Scanner 與一個錯誤地從 Read 返回負數的無效 io.Reader 一起使用時,Scanner 不再會發生 panic,而是返回新的錯誤 ErrBadReadCount。
context
現在明確禁止使用 nil 父級建立派生的 Context。任何嘗試使用 WithValue、WithDeadline 或 WithCancel 函式執行此操作都會導致 panic。
crypto
crypto/rsa、crypto/ecdsa 和 crypto/ed25519 包中的 PrivateKey 和 PublicKey 型別現在具有一個 Equal 方法,用於比較金鑰是否等效或為公鑰建立型別安全介面。該方法簽名與 go-cmp 的相等定義相容。
Hash 現在實現了 fmt.Stringer。
crypto/ecdsa
新的 SignASN1 和 VerifyASN1 函式允許以標準 ASN.1 DER 編碼生成和驗證 ECDSA 簽名。
crypto/elliptic
新的 MarshalCompressed 和 UnmarshalCompressed 函式允許以壓縮格式編碼和解碼 NIST 橢圓曲線點。
crypto/rsa
VerifyPKCS1v15 現在根據 RFC 8017 拒絕缺少前導零的無效短簽名。
crypto/tls
新的 Dialer 型別及其 DialContext 方法允許使用上下文連線和與 TLS 伺服器握手。
Config 型別上的新 VerifyConnection 回撥允許對每個連線進行自定義驗證邏輯。它可以訪問 ConnectionState,其中包括對等證書、SCT 和附加的 OCSP 響應。
自動生成的會話票證金鑰現在每 24 小時自動輪換一次,有效期為 7 天,以限制它們對前向保密性的影響。
TLS 1.2 及更早版本中會話票證的有效期(其中會話金鑰用於恢復連線)現在限制為 7 天,同樣是為了限制它們對前向保密性的影響。
現在強制執行 RFC 8446 中規定的客戶端降級保護檢查。這可能會導致客戶端遇到表現為未經授權的降級攻擊的中介軟體時出現連線錯誤。
SignatureScheme、CurveID 和 ClientAuthType 現在實現了 fmt.Stringer。
客戶端恢復連線時,ConnectionState 欄位 OCSPResponse 和 SignedCertificateTimestamps 現在會重新填充。
tls.Conn 現在對永久性損壞的連線返回一個不透明錯誤,包裝了臨時的 net.Error。要訪問原始的 net.Error,請使用 errors.As(或 errors.Unwrap)而不是型別斷言。
crypto/x509
如果證書上的名稱或正在驗證的名稱(使用 VerifyOptions.DNSName 或 VerifyHostname)無效,它們現在將不區分大小寫地進行比較,不進行進一步處理(不遵守萬用字元或去除尾隨點)。無效名稱包括那些包含除字母、數字、連字元和下劃線之外的任何字元的名稱,那些帶有空標籤的名稱,以及證書上帶有尾隨點的名稱。
新的 CreateRevocationList 函式和 RevocationList 型別允許建立符合 RFC 5280 的 X.509 v2 證書吊銷列表。
如果模板是 CA 並且未明確指定 SubjectKeyId,則 CreateCertificate 現在會自動生成它。
如果模板指定 MaxPathLen 但不是 CA,則 CreateCertificate 現在會返回錯誤。
在 macOS 以外的 Unix 系統上,SSL_CERT_DIR 環境變數現在可以是冒號分隔的列表。
在 macOS 上,二進位制檔案現在總是與 Security.framework 連結,以提取系統信任根,無論 cgo 是否可用。由此產生的行為應與作業系統驗證器更一致。
crypto/x509/pkix
如果 ExtraNames 為 nil,則 Name.String 現在會列印 Names 中的非標準屬性。
database/sql
新的 DB.SetConnMaxIdleTime 方法允許在連線空閒一段時間後將其從連線池中移除,而不考慮連線的總壽命。DBStats.MaxIdleTimeClosed 欄位顯示由於 DB.SetConnMaxIdleTime 關閉的連線總數。
新的 Row.Err getter 允許在不呼叫 Row.Scan 的情況下檢查查詢錯誤。
database/sql/driver
Conn 可以實現新的 Validator 介面,以允許驅動程式指示連線是否有效或是否應丟棄。
debug/pe
該包現在定義了 PE 檔案格式使用的 IMAGE_FILE、IMAGE_SUBSYSTEM 和 IMAGE_DLLCHARACTERISTICS 常量。
encoding/asn1
Marshal 現在根據 X.690 DER 對 SET OF 的元件進行排序。
Unmarshal 現在拒絕不符合 X.690 DER 最小編碼的標籤和物件識別符號。
encoding/json
該包現在在解碼時對最大巢狀深度有一個內部限制。這減少了深度巢狀的輸入可能使用大量堆疊記憶體,甚至導致“goroutine stack exceeds limit”恐慌的可能性。
flag
當 flag 包看到 -h 或 -help,並且這些標誌未定義時,它現在會列印用法訊息。如果 FlagSet 是使用 ExitOnError 建立的,則 FlagSet.Parse 將以狀態 2 退出。在此版本中,-h 或 -help 的退出狀態已更改為 0。特別是,這適用於命令列標誌的預設處理。
fmt
列印動詞 %#g 和 %#G 現在保留浮點值的尾隨零。
go/format
Source 和 Node 函式現在在格式化 Go 原始碼時將數字字面量字首和指數規範化。這與 自 Go 1.13 以來實現的 gofmt 命令的行為一致。
html/template
該包現在在所有 JavaScript 和 JSON 上下文中使用 Unicode 轉義 (\uNNNN)。這修復了 application/ld+json 和 application/json 上下文中的轉義錯誤。
io/ioutil
TempDir 和 TempFile 現在拒絕包含路徑分隔符的模式。也就是說,像 ioutil.TempFile("/tmp", "../base*") 這樣的呼叫將不再成功。這可以防止意外的目錄遍歷。
math/big
新的 Int.FillBytes 方法允許序列化到固定大小的預分配位元組切片。
math/cmplx
此包中的函式已更新,以符合 C99 標準(附錄 G IEC 60559 相容的複數演算法),涉及處理特殊引數,例如無窮大、NaN 和帶符號的零。
net
如果 I/O 操作超出由 Conn.SetDeadline、Conn.SetReadDeadline 或 Conn.SetWriteDeadline 方法設定的截止時間,它現在將返回一個等同於或包裝 os.ErrDeadlineExceeded 的錯誤。這可用於可靠地檢測錯誤是否是由於超出截止時間造成的。早期版本建議在錯誤上呼叫 Timeout 方法,但 I/O 操作可以返回錯誤,即使未超出截止時間,Timeout 也返回 true。
新的 Resolver.LookupIP 方法支援特定於網路且接受上下文的 IP 查詢。
net/http
解析現在更嚴格,作為針對請求走私攻擊的強化措施:非 ASCII 空格不再像 SP 和 HTAB 一樣被修剪,並且放棄了對“identity” Transfer-Encoding 的支援。
net/http/httputil
ReverseProxy 現在支援在 Request.Header 對映中該欄位的傳入條目為 nil 時不修改 X-Forwarded-For 標頭。
當由 ReverseProxy 處理的切換協議(如 WebSocket)請求被取消時,後端連線現在已正確關閉。
net/http/pprof
所有配置檔案端點現在都支援一個“seconds”引數。當存在時,端點會為指定的秒數進行配置檔案分析並報告差異。cpu 配置檔案和跟蹤端點中“seconds”引數的含義不變。
net/url
新的 URL 欄位 RawFragment 和方法 EscapedFragment 提供了有關特定片段精確編碼的詳細資訊和控制。這些類似於 RawPath 和 EscapedPath。
新的 URL 方法 Redacted 返回以字串形式表示的 URL,其中任何密碼都替換為 xxxxx。
os
如果 I/O 操作超出由 File.SetDeadline、File.SetReadDeadline 或 File.SetWriteDeadline 方法設定的截止時間,它現在將返回一個等同於或包裝 os.ErrDeadlineExceeded 的錯誤。這可用於可靠地檢測錯誤是否是由於超出截止時間造成的。早期版本建議在錯誤上呼叫 Timeout 方法,但 I/O 操作可以返回錯誤,即使未超出截止時間,Timeout 也返回 true。
os 和 net 包現在會自動重試因 EINTR 失敗的系統呼叫。以前這會導致虛假故障,在 Go 1.14 中新增非同步搶佔後變得更加常見。現在這已透明處理。
os.File 型別現在支援 ReadFrom 方法。這允許在某些系統上使用 io.Copy 將資料從一個 os.File 複製到另一個 os.File 時使用 copy_file_range 系統呼叫。結果是 io.CopyBuffer 在複製到 os.File 時不總是使用提供的緩衝區。如果程式想要強制使用提供的緩衝區,可以透過寫入 io.CopyBuffer(struct{ io.Writer }{dst}, src, buf) 來完成。
外掛
在 macOS 上,對於 -buildmode=plugin,現在支援 DWARF 生成(並且預設啟用)。
在 freebsd/amd64 上,現在支援使用 -buildmode=plugin 進行構建。
reflect
reflect 包現在禁止訪問所有非匯出欄位的方法,而以前它允許訪問非匯出、嵌入欄位的方法。依賴於先前行為的程式碼應更新為轉而訪問 enclosing 變數的相應提升方法。
regexp
新的 Regexp.SubexpIndex 方法返回給定名稱的第一個子表示式在正則表示式中的索引。
runtime
包括 ReadMemStats 和 GoroutineProfile 在內的幾個函式,如果正在進行垃圾回收,則不再阻塞。
runtime/pprof
goroutine 配置檔案現在包括分析時與每個 goroutine 關聯的配置檔案標籤。此功能尚未在 debug=2 報告的配置檔案中實現。
strconv
添加了 FormatComplex 和 ParseComplex 用於處理複數。
FormatComplex 將複數轉換為 (a+bi) 形式的字串,其中 a 和 b 是實部和虛部。
ParseComplex 將字串轉換為指定精度的複數。ParseComplex 接受 N+Ni 格式的複數。
sync
新的方法 Map.LoadAndDelete 原子地刪除一個鍵並返回先前的存在值(如果存在)。
方法 Map.Delete 更高效。
syscall
在 Unix 系統上,使用 SysProcAttr 的函式現在將拒絕同時設定 Setctty 和 Foreground 欄位的嘗試,因為它們都使用 Ctty 欄位但以不相容的方式。我們預計很少有現有程式會同時設定這兩個欄位。
設定 Setctty 欄位現在要求 Ctty 欄位設定為子程序中的檔案描述符號,由 ProcAttr.Files 欄位確定。使用子描述符始終有效,但在某些情況下,使用父檔案描述符也恰好有效。一些設定 Setctty 的程式將需要更改 Ctty 的值以使用子描述符號。
現在可以在 windows/amd64 上呼叫返回浮點值的系統呼叫。
testing
testing.T 型別現在有一個 Deadline 方法,報告測試二進位制檔案將超出其超時的時間。
TestMain 函式不再需要呼叫 os.Exit。如果 TestMain 函式返回,測試二進位制檔案將使用 m.Run 返回的值呼叫 os.Exit。
新的方法 T.TempDir 和 B.TempDir 返回臨時目錄,這些目錄在測試結束時會自動清理。
go test -v 現在按測試名稱對輸出進行分組,而不是在每行上列印測試名稱。
text/template
JSEscape 現在始終使用 Unicode 轉義 (\u00XX),這與 JSON 相容。
time
新的方法 Ticker.Reset 支援更改計時器的持續時間。
返回錯誤時,ParseDuration 現在會引用原始值。