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
移植支援在 32 位元的 ARM 晶片上執行 Go 的 Windows 10 IoT Core,例如 Raspberry Pi 3。
AIX
Go 現可在 POWER8 架構(aix/ppc64
)中支援 AIX 7.2 以上版本。然而,外部連結、cgo、pprof 和競賽偵測仍不支援。
Darwin
Go 1.12 是最後一個可在 macOS 10.10 Yosemite 上執行的版本。Go 1.13 將需要 macOS 10.11 El Capitan 或更高版本。
現在在 Darwin 上執行的系統呼叫會使用 libSystem
,確保與未來版本的 macOS 和 iOS 相容。轉移至 libSystem
會觸發 App Store 針對私人 API 使用情況進行額外檢查。由於它被視為私人使用,syscall.Getdirentries
現在會在 iOS 上永遠傳回 ENOSYS
。此外,syscall.Setrlimit
會在過去成功的地方回報錯誤的 argument
。這些後果與 Go 無關,而且使用者應預期往後與 libSystem
的實作具有行為相等性。
工具
go tool vet
不再支援
go vet
指令已被改寫為各種不同原始碼分析工具的基礎。請參閱 golang.org/x/tools/go/analysis 套件以取得詳情。這造成副作用是,go tool vet
不再受到支援。使用 go tool vet
的外部工具必須變更為使用 go vet
。在所有支援版本的 Go 中,使用 go vet
取代 go tool vet
應該也能適用。
做為這個變更的一部分,實驗性的 -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 mod edit -go=1.11
使用 Go 1.12 go 工具將語言版本設為 1.11 來避免這個問題。
如果無法使用 active 模組來解析匯入,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
報告。它們也不會列印在恐慌堆疊追蹤中。此變更將 gc
工具鏈調整為與 gccgo
工具鏈相符,後者已經在堆疊追蹤中省略此類封裝程序。這些 API 的客戶端可能需要針對遺失的框架進行調整。對於必須在 1.11 和 1.12 版之間進行互操作的程式碼,您可以使用函式字面 func (...) { x.M(...) }
替換方法表達式 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
不再具有命令列介面,而且只是一個網站伺服器。使用者應使用 go
doc
代替,來輸出命令列說明。Go 1.12 是包含 godoc
網站伺服器的最後一個版本;在 Go 1.13 中,它將透過 go
get
取得。
現在 go
doc
支援 -all
旗標,這會讓它列印所有匯出的 API 及其文件,就像 godoc
命令列過去執行的操作一樣。
go
doc
現在也包含 -src
旗標,它將顯示目標的原始程式碼。
追蹤
追蹤工具現在支援繪製突變器的使用率曲線,包括執行追蹤的交叉參照。它們有助於分析垃圾收集器對應用程式延遲和通量帶來的影響。
組譯器
在 arm64
上,平台暫存器已從 R18
重新命名為 R18PLATFORM
以防止意外使用,因為作業系統可能會選擇保留該暫存器。
執行期間
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
根據 RFC 8446 的規定,Go 1.12 於 crypto/tls
套件中新增了 TLS 1.3 的選擇性支援。若要啟用,請將值 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
Reader
的 UnreadRune
和 UnreadByte
方法現在會傳回錯誤,如果它們在 Peek
之後被呼叫。
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 相較低
- int、float 和字串按 < 排序
- NaN 相較非 NaN float 為低
- bool 相較時 false 在 true 之前
- Complex 相較時先比 real,再比 imaginary
- 指標按機器位址相較
- 通道值按機器位址相較
- 結構依序相較每個欄位
- 陣列依序相較每個元素
- 介面值首先按描述具體類型的
reflect.Type
相較,然後按具體值(如前述規則中所述)相較。
在列印地圖時,先前會將非反身的金鑰值(如 NaN
)顯示為 <nil>
。在此版本中,將列印正確的值。
go/doc
為了解決 cmd/doc
中的一些未解決問題,此套件有新的 Mode
位元,PreserveAST
,可用於控制是否清除 AST 資料。
go/token
File
類型有一個新的 LineStart
欄位,用於傳回特定行開頭的位置。這對於偶爾處理非 Go 檔案(例如組譯)但想使用 token.Pos
機制識別檔案位置的程式特別有用。
image
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 錯誤要求」回應寄送至 HTTPS 伺服器的錯誤 HTTP 要求。
新的 Client.CloseIdleConnections
方法會呼叫 Client
底層 Transport
的 CloseIdleConnections
(若有)。
Transport
不再拒絕宣告 HTTP 尾端資訊但未使用區塊編碼的 HTTP 回應。現在僅會忽略已宣告的尾端資訊。
Transport
不再如在 Go 1.10 和 Go 1.11 中那麼嚴格地處理由 HTTP/2 伺服器宣告的 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 控制字元的 URL (包括 NULL、tab 和換行符號) 傳回錯誤。
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
當傳入 Windows 上的保留檔名(例如 NUL
)時,IsAbs
函式如今會傳回 true。 保留名稱清單。
reflect
新的 MapIter
類型是資料範圍的迭代器. 此類型透過 Value
類型的 MapRange
方法公開. 它遵循和範圍語句相同的迭代語意,用 Next
推進迭代器,用 Key
/Value
存取各個條目。
regexp
Copy
不再需要用來避免鎖定競爭,因此已給予部分不推荐使用的註解. Copy
可能仍適用於使用它的原因是製作兩個具有不同 Longest
設定的副本。
runtime/debug
新的 BuildInfo
類型公開從執行中的二進檔讀取的組建資訊,只在以模組支援組建的二進檔中可用. 這包括主套件路徑、主模組資訊和模組相依關係. 此類型透過 ReadBuildInfo
函式在 BuildInfo
上給予。
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 socket (AF_UNIX
) 位址系列。
新的函數 Syscall18
已於 Windows 中推出,允許呼叫具有最多 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
在執行範本時,長內容值不再會在錯誤中被截斷。
於 <<.very.deep.context.v...> 執行「tmpl」時:映射沒有「notpresent」鍵的項目
現在變為
於 <<.very.deep.context.value.notpresent> 執行「tmpl」時:映射沒有「notpresent」鍵的項目
如果範本呼叫時發生自定義函式的程序錯誤,現下這個錯誤會被 Execute
或 ExecuteTemplate
方法偵測到並傳回為一個錯誤。
時間
$GOROOT/lib/time/zoneinfo.zip
中的時間資料庫已更新為 2018i 版本。請注意,只有當作業系統未提供時,才會使用此 ZIP 檔案。
不安全
將 nil 的 unsafe.Pointer
轉換成 uintptr
並使用算術運算還原是不正確的。(這種情形原本就是不正確的,但現在會導致編譯器產生異常的狀況。)