Go 1.6 發布資訊
Go 1.6 簡介
最新版 Go,1.6,於 1.5 發布後六個月問世。大部分的變動在於語言、執行時間和函式庫的實作。語言規範並無變動。一如往常,此次發布版本維持 Go 1 相容性承諾。我們預期所有 Go 程式幾乎都能繼續編譯並執行,就像先前一樣。
此版本新增了下列功能:64 位元 MIPS 上的 Linux 以及 32 位元 x86 上的 Android 的新移植;定義並強制執行 與 C 共用 Go 指標的規則;HTTP/2 的透明自動支援;以及 範本重複利用 的新機制。
語言變更
此次發布版本並無語言變更。
移植
Go 1.6 新增試驗性的移植至 64 位元 MIPS 上的 Linux(linux/mips64
和 linux/mips64le
)。這些移植支援 cgo
,但僅限於內部連結。
Go 1.6 也新增了一個試驗性移植至 32 位元 x86 上的 Android(android/386
)。
在 FreeBSD 上,Go 1.6 預設使用 clang
而非 gcc
作為外部 C 編譯器。
在 little-endian 64 位元 PowerPC 上的 Linux(linux/ppc64le
),Go 1.6 現在支援具有外部連結的 cgo
,並且功能大致齊全。
在 NaCl 上,Go 1.5 需要 SDK 版本 pepper-41。Go 1.6 新增了對後續 SDK 版本的支援。
在使用 -dynlink
或 -shared
編譯模式的 32 位元 x86 的系統中,特定記憶體參考現在會覆寫 CX 暫存器,因此在手動撰寫組合語言時應避免使用。詳細資料請參閱組合語言文件。
工具
Cgo
cgo
有兩個重要變更,以及一個次要變更。
重要的變更為定義與 C 程式碼共用 Go 指標的規則,以確保該 C 程式碼能夠與 Go 的垃圾回收機制共存。簡而言之,Go 和 C 可在「指到該記憶體的指標作為 cgo
呼叫的一部分傳遞給 C」的情況下,共用由 Go 所配置的記憶體,前提是該記憶體本身不包含指到 Go 配置記憶體的指標,且在呼叫返回後,由 C 保留的指標不會存在。這些規則在程式執行期間由時間執行:如果執行時間偵測到違規,則會印出診斷並讓程式崩潰。設定環境變數 GODEBUG=cgocheck=0
能夠停用這些檢查,但請注意,絕大多數被檢查識別的程式碼在各種方式上都與垃圾回收機制有不合的地方。停用這些檢查通常只會導致較難理解的錯誤模式。強烈建議修正相關程式碼,而不是關閉這些檢查。有關更多詳細資訊,請參閱cgo
文件。
次要的變更為加入明確的 C.complexfloat
和 C.complexdouble
型別,與 Go 的 complex64
和 complex128
分開。與其他數字型別一樣,C 的複雜型別和 Go 的複雜型別不再可互換。
編譯器工具鏈
編譯器工具鏈幾乎沒有改變。在內部,最重要的變更為剖析器現在為親自撰寫,不再從 yacc 產生。
編譯器、連結器和 go
指令有一個新旗標 -msan
,類似 -race
且僅在 linux/amd64 中可用,可以啟用與Clang MemorySanitizer 的互通。這種互通主要用於測試包含可疑 C 或 C++ 程式碼的程式。
連結器有一個新選項 -libgcc
,連結cgo
程式碼時,可設定 C 編譯器支援函式庫預期位置。在使用時才會查詢此選項 -linkmode=internal
,並可將其設定為 none
以停用支援函式庫。
組建模式 (在 Go 1.5 中開始) 的實作已擴充至更多系統。此版本增加了對 android/386
、android/amd64
、android/arm64
、linux/386
和 linux/arm64
的 c-shared
模式支援,對 linux/386
、linux/arm
、linux/amd64
和 linux/ppc64le
的 shared
模式支援;還有 android/386
、android/amd64
、android/arm
、android/arm64
、linux/386
、linux/amd64
、linux/arm
、linux/arm64
和 linux/ppc64le
的新 pie
模式支援 (產生與位置無關的可執行檔)。詳細資訊請參閱設計文件。
提醒您,連結器的 -X
記號已在 Go 1.5 中變更。在 Go 1.4 及更早的版本中,它接受兩個引數,如下
-X importpath.name value
Go 1.5 新增另一種語法使用單一引數,它本身就是 名稱=值
對
-X importpath.name=value
在 Go 1.5 的版本中,舊語法仍然可以接受,列印出建議使用新語法的警告訊息後。Go 1.6 仍然接受舊語法,並列印警告。Go 1.7 將移除對舊語法的支援。
Gccgo
GCC 及 Go 專案的版本計畫並不一致。GCC 版本 5 包含 gccgo 的 Go 1.4 版本。下一個版本,GCC 6,將會有 gccgo 的 Go 1.6.1 版本。
Go 指令
go
指令的基本操作仍然沒有改變,但是有些變更是值得注意的。
Go 1.5 引進對供應商的實驗性支援,透過將 GO15VENDOREXPERIMENT
環境變數設定為 1
來啟用。Go 1.6 保留供應商的支援,不再視為實驗性質,並預設啟用。您可以透過將 GO15VENDOREXPERIMENT
環境變數設定為 0
來明確停用。Go 1.7 將移除對環境變數的支援。
預設啟用供應商最可能會在包含現有命名為 供應商
目錄(不預期根據新的供應商語意來詮釋)的原始碼樹中造成問題。在這種情況下,最簡單的解決方法是將目錄名稱變更為 供應商
以外的任何名稱,並更新任何受影響的匯入路徑。
有關供應商的詳細資訊,請參閱 go
指令 及 設計文件 的文件。
有一個新的建置標記,-msan
,它會編譯具有支援 LLVM 記憶消毒功能的 Go。這主要是打算在連結對照使用記憶消毒來檢查的 C 或 C++ 程式碼時使用。
Go 文件指令
Go 1.5 引進 go 文件
指令,它允許僅使用套件名稱來參照套件,如 go
文件
http
。如果發生歧義,Go 1.5 的行為是使用字典序最早的匯入路徑的套件。在 Go 1.6 中,歧義會透過偏好具有較少元素的匯入路徑來解決,並使用字典序比較來打破僵局。此變更的一個重要影響是,現在偏愛套件的原始副本,而不偏愛供應商的副本。成功的搜尋也傾向於執行得更快。
Go vet 指令
go vet
指令現在會診斷將函式或方法值傳遞作為 Printf
的引數,例如傳遞 f
,而 f()
是預期的。
效能
一如往常,變更非常一般且差異很大,因此難以的確切說明效能。某些程式可能會執行得更快,某些程式則會執行得更慢。平均而言,Go 1 效能基準測試套件中的程式在 Go 1.6 的執行速度比在 Go 1.5 時快了幾個百分點。垃圾回收暫停時間甚至比 Go 1.5 時更短,尤其是對於使用大量記憶體的程式。
已經進行重大最佳化,對於下列套件的實作帶來超過 10% 的改善:compress/bzip2
、compress/gzip
、crypto/aes
、crypto/elliptic
、crypto/ecdsa
和 sort
。
標準函式庫
HTTP/2
Go 1.6 在 net/http
套件中為新的 HTTP/2 協定 加入透明支援。使用 HTTPS 時,Go 執行個體和伺服器將自動在適當時使用 HTTP/2。沒有針對 HTTP/2 協定處理之詳細資訊而匯出的 API,就像沒有針對 HTTP/1.1 而匯出的 API 一樣。
必須停用 HTTP/2 的程式可以透過設定 Transport.TLSNextProto
(對於執行個體)或 Server.TLSNextProto
(對於伺服器)為非 nil 的空地圖來做到。
必須調整 HTTP/2 協定特定詳細資訊的程式可以匯入並使用 golang.org/x/net/http2
,尤其是它的 ConfigureServer 和 ConfigureTransport 函式。
執行時期
執行時期已加入輕量級的最佳化 प्रयास,用來偵測並發程式碼濫用地圖。一如往常一樣,如果一個 goroutine 寫入一個地圖,就不應有任何其他 goroutine 同時讀取或寫入該地圖。如果執行時期偵測到此情況,它會印出一份診斷結果,然後讓程式發生故障。找出此問題的最佳方式是使用 競爭偵測器 執行程式,它將更加可靠地識別競爭條件並提供更詳細的資訊。
對於會終止程式的意外事件,執行時期現在預設只會印出執行中 goroutine 的堆疊,而不是所有現有的 goroutine。通常只有一個目前的 goroutine 與意外事件有關,因此遺漏其他 goroutine 可大幅減少發生故障訊息中的無關輸出。若要於故障訊息中看到所有 goroutine 的堆疊,請將環境變數 GOTRACEBACK
設定為 all
,或在發生故障前呼叫 debug.SetTraceback
,然後重新執行程式。請參閱 執行時期文件以瞭解詳細資訊。
更新:預計轉儲整個程式狀態的未捕捉到錯誤,例如偵測到逾時或明確處理接收到的訊號時,現在應先呼叫 debug.SetTraceback("all")
,然後才發生錯誤。搜尋 signal.Notify
的用途可能有助於找出這種程式碼。
在 Windows 上,Go 1.5 及稍早版本的 Go 程式會在啟動時透過呼叫 timeBeginPeriod(1)
將整體 Windows 計時器解析度強制設定為 1ms。Go 不再需要此動作來獲得良好的排程器效能,而變更整體計時器解析度會在某些系統上造成問題,因此已移除這項呼叫。
使用 -buildmode=c-archive
或 -buildmode=c-shared
來建置封存或共享函式庫時,訊號處理已經變更。在 Go 1.5 中,封存或共享函式庫會為大多數訊號安裝訊號處理常式。在 Go 1.6 中,將只會為同步訊號安裝訊號處理常式,以處理 Go 程式碼中的執行時期錯誤:SIGBUS、SIGFPE、SIGSEGV。查看 os/signal 套件以取得更多詳細資料。
反射
reflect
套件已 解決 gc 與 gccgo 工具鏈之間的長期不相容性,其關於包含匯出的欄位的嵌入式未匯出結構體類型。使用反射來存取資料結構的程式碼,尤其是在遵循 encoding/json
和 encoding/xml
套件的精神實作序列化的程式碼,可能需要更新。
當使用反射在嵌入式未匯出結構體類型欄位中存取該結構體的匯出欄位時,就會產生問題。在此情況下,reflect
錯誤地將嵌入式欄位報告為匯出,但回傳一個空的 Field.PkgPath
。現在,它會正確地將欄位報告為未匯出,但在評估存取結構體內包含的匯出欄位時,會忽略此事實。
更新:通常,先前遍歷結構體並使用
f.PkgPath != ""
來排除無法存取的欄位的程式碼,現在應使用
f.PkgPath != "" && !f.Anonymous
例如,請參閱 encoding/json
和 encoding/xml
的實作變更。
排序
在 sort
套件中,Sort
的實作已被改寫,以減少大約 10% 對 Interface
的 Less
和 Swap
方法的呼叫,並產生相應的整體時間節省。新的演算法確實會對比較相等的數值(這些配對 Less(i,
j)
和 Less(j,
i)
為 false)選擇與之前不同的排序方式。
更新中:Sort
的定義不保證相等值最後的順序,但新的行為仍可能中斷期待特定順序的程式。此類程式應該修改其 Less
實作以回報想要的順序,或應該切換到會保留相等值原始輸入順序的 Stable
。
範本
在 text/template 套件中,有兩個重要的新功能可簡化範本撰寫工作。
首先,現在可以 調整範本動作周圍的空白,可讓範本定義更易讀。動作開頭的減號表示在動作前移除空白,而動作結尾的減號表示在動作後移除空白。例如,範本
{{23 -}}
<
{{- 45}}
格式化為 23<45
。
其次,新的 {{block}}
動作,加上允許重新定義命名範本,提供定義範本區塊的簡單方式,這些範本區塊可在不同的實例化中取代。text/template
套件中有一個 範例 展示此新功能。
函式庫的次要變更
archive/tar
套件的實作修正檔案格式中許多罕見案例中的錯誤。一個明確的變更為:Reader
類型的Read
方法現在將特殊檔案類型內容呈現為空白,立即傳回io.EOF
。- 在
archive/zip
套件中,Reader
類型現在具有RegisterDecompressor
方法,而Writer
類型現在具有RegisterCompressor
方法,能控制各別 zip 檔案的壓縮選項。這些選項優先於先前存在的全域RegisterDecompressor
和RegisterCompressor
函式。 bufio
套件的Scanner
類型現在具有Buffer
方法,可用於指定在掃描時使用的初始緩衝區和最大緩衝區大小。這允許在需要時掃描比MaxScanTokenSize
大的符號。對於Scanner
,該套件現在定義ErrFinalToken
錯誤值,供 分割函式 使用,以中止處理或傳回最後一個空白符號。compress/flate
套件已棄用其ReadError
和WriteError
錯誤實作。在 Go 1.5 中,這些實作僅在發生錯誤時才會逐漸傳回;現在這兩個實作已不再傳回,雖然仍為相容性保留。- 現在,
compress/flate
、compress/gzip
和compress/zlib
套件會針對截斷的輸入串流回報io.ErrUnexpectedEOF
,而非io.EOF
。 - 現在,
crypto/cipher
套件會在發生 GCM 解密失敗時覆寫目標緩衝區。這是為了讓 AESNI 程式碼避免使用暫時緩衝區。 - 現在,
crypto/tls
套件有多項次要變更。現在,當Config
的Certificates
為 nil,且已設定GetCertificate
回呼,它就能讓Listen
成功;它新增了對 RSA 與 AES-GCM cipher 套件的支援,且新增RecordHeaderError
,讓用戶端 (特別是net/http
套件) 能針對嘗試與非 TLS 伺服器建立 TLS 連線時,回報更好的錯誤訊息。 - 現在,
crypto/x509
套件允許憑證包含負序號 (技術上而言是錯誤的,但很不幸的,在實際使用上很常見),且它定義了一個新的InsecureAlgorithmError
,當拒絕一個使用不安全的演算法 (例如 MD5) 所簽署的憑證時,能提供更好的錯誤訊息。 - 現在,
debug/dwarf
和debug/elf
套件已新增對壓縮 DWARF 區段的支援。使用者程式碼不需要更新:在讀取時,區段將自動解壓縮。 - 現在,
debug/elf
套件已新增對一般壓縮 ELF 區段的支援。使用者程式碼不需要更新:在讀取時,區段將自動解壓縮。不過,壓縮的Sections
不支援隨機存取:它們有一個 nil 的ReaderAt
欄位。 - 現在,
encoding/asn1
套件會匯出 標記和類別常數,這對進階的 ASN.1 結構剖析非常有用。 - 同樣在
encoding/asn1
套件中,現在,Unmarshal
會拒絕各種非標準的整數和長度編碼。 - 已修正
encoding/base64
套件的Decoder
,以處理它輸入的最後幾個位元組。過去,它會處理盡可能多的四位元組記號,但忽略最多三個位元組的其餘部分。因此,現在Decoder
可以正確地處理未補齊編碼 (例如 RawURLEncoding) 的輸入,但它也會拒絕補齊編碼中被截斷或以無效位元組結束的輸入,例如尾隨的空格。 - 在將
Number
編組之前,encoding/json
封裝現在會檢查其語法,要求它符合數值 JSON 規格。與先前版本一樣,零Number
(空字串)會編組為字面 0(零)。 - 現在,
encoding/xml
封裝的Marshal
函數支援cdata
屬性,例如chardata
,但會使用一個或多個<![CDATA[ ... ]]>
標記編碼其引數。 - 同樣在
encoding/xml
封裝中,Decoder
的Token
方法現在會在所有開啟的標記看到都全部關閉之前遇到 EOF 時報告一個錯誤,這與其一般要求輸入中的標記已正確配對相符。若要避免該要求,請使用RawToken
。 - 現在,
fmt
封裝允許任何整數類型作為Printf
的*
寬度和精度規範的引數。在先前版本中,*
的引數要求類型為int
。 - 同樣在
fmt
封裝中,現在Scanf
可以使用 %X 掃描十六進位字串,作為 %x 的別名。兩種格式都接受十六進位的大寫和小寫的任意組合。 - 現在,
image
和image/color
封裝新增NYCbCrA
和NYCbCrA
類型,以支援具有非預先相乘 alpha 的 Y’CbCr 影像。 - 現在,
io
封裝的MultiWriter
執行已執行一個WriteString
方法,供WriteString
使用。 - 在
math/big
封裝中,Int
新增Append
和Text
方法,提供更能控制印出的功能。 - 同樣在
math/big
封裝中,Float
現在執行encoding.TextMarshaler
和encoding.TextUnmarshaler
,允許它以自然形式由encoding/json
和encoding/xml
封裝序列化。 - 同樣在
math/big
封裝中,Float
的Append
方法現在支援特殊精度引數 -1。與strconv.ParseFloat
相同,精度 -1 表示使用必要的最小數位,才使得讀取結果的Parse
轉換為具有相同精度的Float
時會產生原始值。 math/rand
套件新增Read
函式,類似地,Rand
新增Read
方法。這使得產生偽隨機測試資料變得更加容易。請注意,與套件中的其他部分一樣,這些不應該用在密碼學設定中;對於此類目的用途,請改用crypto/rand
套件。net
套件的ParseMAC
函式現在接受 20 位元組的 IP 透過 InfiniBand (IPoIB) 連結層位址。- 在
net
套件中,DNS 查詢也進行了一些變更。首先,DNSError
錯誤實作現在實作Error
,特別是它的新IsTemporary
方法對 DNS 伺服器錯誤傳回 true。其次,像LookupAddr
這類 DNS 查詢函式現在會在 Plan 9 和 Windows 傳回根網域名稱(後方加上一個點),以符合 Go 在 Unix 系統上的行為。 net/http
套件有許多次要的增強,除了先前討論過的 HTTP/2 支援以外。首先,FileServer
現在會依檔案名稱對其產生的目錄清單進行排序。其次,ServeFile
函式現在會拒絕提供服務,如果要求的 URL 路徑包含「..」(兩個點)作為路徑元素。程式通常應該使用FileServer
和Dir
,而不直接呼叫ServeFile
。需要以檔案內容提供服務來回應包含雙點 URL 要求的程式仍然可以呼叫ServeContent
。第三,Client
現在允許使用者程式設定Expect:
100-continue
標頭(參閱Transport.ExpectContinueTimeout
)。第四,有 五個新的錯誤碼:來自 RFC 6585 的StatusPreconditionRequired
(428)、StatusTooManyRequests
(429)、StatusRequestHeaderFieldsTooLarge
(431) 和StatusNetworkAuthenticationRequired
(511),以及最近核准的StatusUnavailableForLegalReasons
(451)。第五,CloseNotifier
的實作和文件已經大幅變更。Hijacker
介面現在能夠正確處理之前已與CloseNotifier
一起使用的連線。文件中現在描述CloseNotifier
預期何時運作。- 在
net/http
套件中也有幾個與處理Request
資料結構有關的變更,其Method
欄位會設定為空字串。空Method
欄位一直都是作為"GET"
的別名文件化的,現在仍保留這個用法。不過,Go 1.6 修正了幾個將空Method
處理得與明確的"GET"
不同的例程。明確來說,在之前版本的Client
中,只有當Method
明確設定為"GET"
時才會追蹤重新導向;而在 Go 1.6 中,Client
也會為空Method
追蹤重新導向。最後,NewRequest
會接受一個文件化為允許留空的method
參數。在過去版本中,傳入空method
參數會導致一個具有空Method
欄位的Request
。在 Go 1.6 中,產生的Request
一律會有一個已初始化的Method
欄位:如果其參數是一個空字串,NewRequest
會將傳回的Request
中的Method
欄位設定為"GET"
。 - 現在,
net/http/httptest
套件的ResponseRecorder
會使用與http.Server
中相同的內容嗅探演算法,初始化預設的 Content-Type 標頭。 - 現在,
net/url
套件的Parse
在解析主機名稱方面更嚴格且更符合規範。舉例來說,主機名稱中的空格不再被接受。 - 同在
net/url
套件中,Error
型別現在實作net.Error
。 - 現在,
os
套件的IsExist
、IsNotExist
和IsPermission
在針對SyscallError
查詢時,會傳回正確的結果。 - 在類 Unix 的系統上,寫入
os.Stdout
或os.Stderr
(更精確地說,是針對檔案描述符 1 或 2 開啟的os.File
)時,如果發生問題導因於錯誤的管線而失敗,程式會發出一則SIGPIPE
訊號。預設情況下,這會導致程式退出;可以透過呼叫os/signal
的Notify
函式來變更此設定,並用於syscall.SIGPIPE
。寫入描述符不為 1 或 2 的錯誤管線時,會單純傳回syscall.EPIPE
(可能包覆在os.PathError
和/或os.SyscallError
內)。舊有行為是:接連 10 次寫入錯誤管線後,發出一則無法捕捉的SIGPIPE
訊號,這種行為不再會發生。 os/exec
套件中的Cmd
的Output
方法在指令碼結束,且狀態不成功時,現在依然會傳回ExitError
。若原本標準錯誤會被捨棄,傳回的ExitError
現在會含有一個前綴及後綴 (目前為 32 kB)的失敗指令碼標準錯誤輸出,用於偵錯或新增至錯誤訊息中。ExitError
的String
方法不會顯示擷取的標準錯誤,程式必須從資料結構中分別擷取。- 在 Windows 中,
path/filepath
套件的Join
函式現在能正確處理基礎是一個相對驅動器路徑的情況。例如,Join(`c:`,
`a`)
現在會傳回`c:a`
,而非舊版中的`c:\a`
。這可能會影響希望看到錯誤結果的程式碼。 regexp
套件中,Regexp
類型向來允許共行常式同時使用。它會使用sync.Mutex
來保護正規表示式搜尋期間使用的暫存空間快取。某些使用來自多個共行的常式、高度共行性的伺服器會因為該 mutex 上的競爭而降低效能。Regexp
現在提供Copy
方法以幫助此類伺服器。它會複製一個Regexp
,共用大部分原先結構,但有它自己的暫存空間快取。兩個共行常式可以使用Regexp
的不同複本,而不會有 mutex 競爭。複本確實會有額外的空間開銷,所以Copy
應該僅在觀察到競爭時使用。strconv
套件新增IsGraphic
,類似於IsPrint
。它也新增QuoteToGraphic
、QuoteRuneToGraphic
、AppendQuoteToGraphic
和AppendQuoteRuneToGraphic
,類似於QuoteToASCII
、QuoteRuneToASCII
。ASCII
系列會跳脫所有空白字元,除了 ASCII 空白 (U+0020)。相對地,Graphic
系列不會跳脫任何 Unicode 空白字元(類別 Zs)。- 在
testing
套件中,當測試呼叫 t.Parallel 時,測試將暫停,直到所有非平行測試完成,然後測試將與其他所有平行測試一起繼續執行。Go 1.6 變更了針對此類測試報告的時間:以前時間只計算平行執行,但現在還計算從測試開始到呼叫t.Parallel
的時間。 - 除了上面描述的 重大變更 之外,
text/template
套件還包含兩項次要變更。首先,它新增了ExecError
新類型,會針對對應於Execute
的任何錯誤傳回,其錯誤並非來自寫入底層撰寫器的Write
。呼叫者可以透過檢查ExecError
來區分範本使用錯誤和 I/O 錯誤。其次,Funcs
方法現在會檢查用於FuncMap
中的金鑰的名稱,並驗證這些名稱是識別碼,而且可以顯示於範本函式呼叫中。如果沒有,Funcs
會驚慌。 time
套件的Parse
函式一向拒絕大於 31 的任何日期,例如 1 月 32 日。在 Go 1.6 中,Parse
現在也會拒絕非閏年的 2 月 29 日、2 月 30 日、2 月 31 日、4 月 31 日、6 月 31 日、9 月 31 日和 11 月 31 日。