[翻譯] Go 1.1 介紹

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

由於年後工作實在太忙,一直也沒寫點什麼。不過這篇我覺得值得,所以……
原文:https://tip.golang.org/hg/doc/go1.1.html
原文連結我進行了替換,現在指向 tip 大多數應該正確吧。不過如果是 Go 1.1 正式發布半年後,我可不保證了。
————翻譯分隔線————

Go 1.1 介紹

Go 第一版(簡稱 Go 1 或 Go 1.0)發佈於 2012 年三月,這個版本提供了穩定的 Go 語言和庫。其穩定性讓全世界 Go 使用者社區和相關係統茁壯成長。從那時起,就發布了若干個“關鍵點”——1.0.1、1.0.2 和 1.0.3。這些點的發布修複了若干已知 bug,但是對於實現本身並沒有進行修改。

這個新的發布版,Go 1.1,在保持相容性的前提下添加了若干重要的(當然,向後相容)語言變化,而庫變化的清單也很長(也向後相容),還有在編譯器、庫和運行時環境實現的主要工作。焦點是效能。測試並不是十分精確,但是對於許多測試程式來說都有著重要的、有時是戲劇性的效能改善。我們相信,通過升級 Go 的安裝包,並且重新編譯,許多使用者的程式也能讓人體會到這一改進。

這一文檔匯總了從 Go 1 到 Go 1.1 的變化。雖然這個發布版有一些極為罕見的錯誤情況,而當這些情況在發生時必須被處理。在 Go 1.1 下運行,幾乎不需要修改任何代碼。下面描述了細節;參閱 64 位元整數和 Unicode 文字的特別說明。

語言的變化

Go 的相容性文檔保證了用 Go 1 語言規範編寫的程式仍然可以使用,並且可以會繼續被維護。儘管有一些細節的錯誤情況已經被指出,但是規範本身的完善還是相當有趣的。同時還增加了一些語言的新特性。

整數除以零

在 Go 1 中,整數被一個常量零整除會產生一個運行時 panic:

func f(x int) int {return x/0}

在 Go 1.1 中,一個整數被一個常量零整除不是合法的程式,因此這會是一個編譯時間錯誤。

代用的 Unicode 文字

細化了 string 和 rune 文字的定義,以便將代用部分排除在合法的 Unicode 編碼值以外。參閱 Unicode 部分瞭解更多資訊。

方法值

現在 Go 1.1 實現了方法值,也就是將函數綁定在特定的接收者的值上。例如,有一個 Writer 的值 w,運算式 w.Write,是一個方法值,作為用於向 w 寫入的函數;這與函數文法中對 w 進行閉包是等價的:

func (p []byte) (n int, err error) {return w.Write(p)}

方法值與方法運算式是不同的,方法運算式從方法中利用指定的類型構造了一個函數;方法運算式 (*bufio.Writer).Write 與第一個參數類型指定為 (*bufio.Writer) 的函數等價:

func (w *bufio.Writer, p []byte) (n int, err error) {return w.Write(p)}

更新:已有代碼不受影響;這個變動是嚴格的向後相容。

Return requirements

在 Go 1.1 之前,一個函數返回一個值必須明確的在函數結束時“return”或調用 panic;這是一個讓程式明確函數的概念的簡單的途徑。但是,顯然有許多情況最後的“return”沒有必要,例如, 一個只有死迴圈“for”的函數。

在 Go 1.1 中,關於最後的“return”語句的規則更加寬鬆。它引入了一個終止語句的概念,它保證了在函數中這個語句總是最後被執行。例如在沒有條件的“for”迴圈中,也沒有“if-else”語句用來在中間通過“return”結束。那麼函數的最後一個語句可以在文法上被認為是終止語句,而不需要最後的“return”語句。

注意這個規則純粹是文法上的:它並不關注代碼中的值,因此也沒有複雜的分析。

更新:這個變動是向後相容的,不過有著多餘“return”語句或調用 panic 的已有代碼可能需要手工處理一下。這些代碼可用 go vet 來標識。

實現和工具的變更

命令列參數解析

在 gc 工具鏈中,編譯器和連結器現在使用與 Go 的 flag 包一致的命令列參數解析規則,而與傳統的 Unix 參數解析背道而馳。這可能會對直接調用工具的指令碼產生影響。例如,go tool 6c -Fw -Dfoo 現在必須寫為 go tool 6c -F -w -D foo

在 64 位元平台上的整數大小

該語言允許根據具體實現選擇 int 類型和 uint 類型是 32 或 64 位元的。之前 Go 的實現是在所有系統上都讓 int 和 uint 是 32 位的。現在 gc 和 gccgo 的實現都讓 int 和 uint 在如 AMD64/x86-64 這樣的平台上是 64 位元的。拋開別的不說,單這個就使得 slice 在 64 位元平台上可以分配超過 20 億的元素。

更新:大多數程式不會受到這個的影響。 由於 Go 不允許不同數字類型之間的隱式轉換,不會有程式在編譯時間報錯。然而,那些隱式假設 int 是 32 位的程式,在行為上可能發生變化。例如,這個程式在 64 位元系統中會列印正數,在 32 位系統中會列印負數:

x := ^uint32(0) // x is 0xffffffffi := int(x)     // i is -1 on 32-bit systems, 0xffffffff on 64-bitfmt.Println(i)

要保留 32 位的符號(在所有系統上都是 -1)應該用下面的具有可移植性的代碼代替:

i := int(int32(x))

Unicode

為了能夠表達 UTF-16 中超過 65535 的編碼值,Unicode 定義了代用部分,一個僅用於組裝更大的值的編碼值範圍,且僅在 UTF-16 中。在這個代用範圍內的編碼值如果用於其他任何情況都是非法的,如作為 UTF-8 編碼,或作為獨立的 UTF-16 編碼。例如在遇到將一個 rune 轉換成 UTF-8 時,它被當作一個編碼錯誤對待,併產生一個替代的 rune,utf8.RuneError, U+FFFD。

這個程式,

import "fmt"func main() {    fmt.Printf("%+q\n", string(0xD800))}

在 Go 1.0 中列印“\ud800”,但在 Go 1.1 中列印“\ufffd”。

半個代用 Unicode 值現在在 rune 和 string 常量中都是非法的,因此如“\ud800”和“\ud800”的常量現在會被編譯器拒絕。當編寫為獨立的 UTF-8 編碼的位元組時,這樣字串還是可以被建立的,例如“\xed\xa0\x80”。然而,當這個字串被作為一個 rune 序列解碼時,比如在 range 迴圈中,它只會產生 utf8.RuneError 值。

Unicode 位元組順序讓 U+FFFE 和 U+FEFF 在 UTF-8 編碼下可以作為 Go 源碼的第一個字元出現。雖然在位元組順序未設定的 UTF-8 編碼中,它是完全不必要的,不過有些編輯器會將其作為“魔法數值”添加進去,用來標識一個 UTF-8 編碼的檔案。

更新:大多數程式不會受到代用變更的影響。基於舊的行為的程式應當通過修改來避免問題。位元組順序標識的變更是嚴格向後相容的。

gc 彙編

基於如 int 到 64 位元和其他一些變化,在 gc 工具鏈的函數參數的棧布局發生了變化。使用彙編編寫的函數至少需要一個 frame 指標位移量。

更新:現在 go vet 命令可以檢查用彙編實現的函數是否匹配 Go 的函數原型。

go 命令的變化

為了讓新的 Go 使用者獲得更好的體驗,go 命令做了若干改動。

首先,當編譯、測試或運行 Go 代碼的時候,go 命令會給出更多的錯誤資訊細節,當一個包無法被定位時,會列出搜尋的路徑清單。

$ go build foo/quxxcan't load package: package foo/quxx: cannot find package "foo/quxx" in any of:        /home/you/go/src/pkg/foo/quxx (from $GOROOT)        /home/you/src/foo/quxx (from $GOPATH)

其次,go get 命令不再允許下載包源碼時,將 $GOROOT 作為預設的目的路徑。要使用 go get 命令,必須有一個合法的 $GOPATH。

$ GOPATH= go get code.google.com/p/foo/quxxpackage code.google.com/p/foo/quxx: cannot download, $GOPATH not set. For more details see: go help gopath

最後,作為前面變化的結果,go get 命令會在 $GOPATH 和 $GOROOT 設定為相同值的時候報錯。

$ GOPATH=$GOROOT go get code.google.com/p/foo/quxxwarning: GOPATH set to GOROOT (/home/User/go) has no effectpackage code.google.com/p/foo/quxx: cannot download, $GOPATH must not be set to $GOROOT. For more details see: go help gopath

go test 命令的變化

go test 命令在進行效能測試時不再刪除二進位內容,以便更容易的分析效能測試。實現上是在啟動並執行時候設定了 -c 參數。

$ go test -cpuprofile cpuprof.out mypackage

go test 運行之後,mypackage.test 將會留在目錄中。

go test 命令現在可以報告 goroutine 在哪裡阻塞的測試資訊,也就是說,它們在哪一直等著某個事件,例如一個 channel 通訊之類的。當用 -blockprofile 開啟 go test 的阻塞測試時,就會展示這些資訊。 運行 go help test 瞭解更多資訊。

go fix 命令的變化

fix 命令通常以 go fix 執行,不再提供從 Go1 之前的版本升級到 Go 1 API 的功能。如果要升級 Go 1 之前的代碼到 Go 1.1,首先應當使用 Go 1.0 的工具鏈,將代碼轉化到 Go 1.0。

效能

用 Go 1.1 的 gc 工具集編譯出來的代碼的效能對於大多數 Go 程式來說應當有顯著的提升。一般來說,與 Go 1.0 相比,大約有 30%-40% 的提升,有時甚至更高,當然也會比這個值低,甚至沒有提升。對於工具和庫來說,有太多的小的效能驅使的改動,以至於無法將它們全部列在這裡。不過下面的主要變更還是有必要留意的:

  • gc 編譯器在大多數情況下都會產生較好的代碼,尤其是在 32 位 Intel 架構下的浮點值。
  • gc 編譯器做了更多的內連,包括在運行時的一些操作,例如 append 和介面轉換。
  • Go 的 map 有了新的實現,在記憶體複製和 CPU 時間上有了重大的改進。
  • 記憶體回收實現了更多的並行,這可以降低在多 CPU 環境下啟動並執行程式的延遲。
  • 記憶體回收同時也更加精準,這增加了一點 CPU 時間開銷,但是極大的降低了堆的大小,尤其是在 32 位的架構下。
  • 通過緊密結合運行時和網路程式庫,在網路操作時需要的環境切換會更少。

標準庫的變化

bufio.Scanner

在 bufio 包中有多種方式擷取文本輸入,ReadBytes、ReadString 和特別的 ReadLine,對於簡單的目的這些都有些過於複雜了。在 Go 1.1 中,添加了一個新類型,Scanner,以便更容易的處理如按行讀取輸入序列或空格分隔的詞等,這類簡單的任務。它終結了如輸入一個很長的有問題的行這樣的輸入錯誤,並且提供了簡單的預設行為:基於行的輸入,每行都剔除分隔標識。這裡的代碼展示來一次輸入一行:

scanner := bufio.NewScanner(os.Stdin)for scanner.Scan() {    fmt.Println(scanner.Text()) // Println will add back the final '\n'}if err := scanner.Err(); err != nil {    fmt.Fprintln(os.Stderr, "reading standard input:", err)}

輸入的行為可以通過一個函數控制,來控制輸入的每個部分(參閱 SplitFunc 的文檔),但是對於複雜的問題或持續傳遞錯誤的,可能還是需要原有介面。

net

在 net 包中的協議特定的解析器之前對傳遞入的網路名稱很寬鬆。雖然文檔明確指出對於 ResolveTCPAddr 合法的網路名稱只有“tcp”,“tcp4”和“tcp6”,Go 1.0 的實現對於任何字串都會接受。而 Go 1.1 的實現,如果網路名稱不在這些字串中,就會返回一個錯誤。這對於其他協議特定的解析器 ResolveIPAddr、ResolveUDPAddr 和 ResolveUnixAddr 也是一樣。

之前的的實現,ListenUnixgram 返回一個 UDPConn 作為接收串連的端點。在 Go 1.1 的實現裡,用 UnixConn 來代替,這允許用它的 ReadFrom 和 WriteTo 方法讀寫。

資料結構 IPAddr、TCPAddr 和 UDPAddr 添加了一個叫做 Zone 的新字串欄位。由於新的欄位,使用沒有標籤的複合文法(例如 net.TCPAddr{ip, port})的代碼代替有標籤的文法(net.TCPAddr{IP: ip, Port: port})會出錯。Go 1 的相容性規則允許這個變化:用戶端代碼必須使用標籤化的文法以避免這種破壞。

更新:為了修正由於新的結構體欄位帶來的破壞,go fix 將會重寫這些類型的代碼以添加標籤。更通用的是,go vet 將會標識出所有應當使用欄位標籤的複合文法。

reflect

reflect 包有若干重大改進。

現在用 reflect 包返回一個“select”語句是可能的;參閱 Select 和 SelectCase 瞭解更多細節。

新的方法 Value.Convert(或 Type.ConvertibleTo)提供了對一個 Value 進行 Go 的轉換和類型斷言操作(或者是檢測這種可能性)的函數方式。

新的函數 MakeFunc 建立了一個使得在已有 Value 上調用函數更加容易的封裝函數,可以用於標準的 Go 參數的轉換,例如將一個 int 傳遞為 interface{}。

最後,新的函數 ChanOf、MapOf 和 SliceOf 可以從已有類型中構造新 Type,例如在僅提供 T 的情況下構造 []T。

time

之前的 time 包在 FreeBSD、Linux、NetBSD、OS X 和 OpenBSD 上精確到微秒。Go 1.1 在這些作業系統上的實現可以精確到納秒。程式用微妙的精確度向外部寫入再讀出,若覆蓋掉原有值的話,將會產生精度的損失。Time 有兩個新方法,Round 和 Truncate,可以用來在向外部儲存寫入前,從時間裡去除精度。

新方法 YearDay 返回指定 time 值在一年中的某天的唯一整數序數。

Timer 類型有一個新方法 Reset,讓定時器在指定的間隔後到期。

最後,一個新函數 ParseInLocation 與已有的 Parse 類似,不過會忽略解析的字串中的時區資訊,而使用傳入的位置(時區)來解析時間。這個函數解決了時間 API 中常見的混亂情況。

更新:對於那些使用更低精度的外部格式來讀寫時間的代碼,應當修改用新的方法。

Exp 舊的代碼樹移動到 go.exp 和 go.text 子版本庫

為了讓使用二進位發布版的使用者在需要的時候訪問更加容易,不包含在二進位發布版的 exp 和舊的源碼樹被移動到新的子版本庫 code.google.com/p/go.exp。舉例來說,如果要訪問 ssa 包,執行

$ go get code.google.com/p/go.exp/ssa

然後在 Go 代碼中,

import "code.google.com/p/go.exp/ssa"

舊的包 exp/norm 也遷移到了新的版本庫 go.text,這裡包含了正在開發的 Unicode API 和其他文本相關的包。

庫的微小變更

下面的清單列出了庫的微小改動,大多數是一些增強。對於每個變更可參閱包相關的文檔瞭解更多資訊。

  • bytes 包有兩個新函數,TrimPrefix 和 TrimSuffix,含義不言而喻。同樣,Buffer 類型有一個新方法 Grow,提供了一些控制緩衝內部記憶體配置的能力。最後,Reader 類型現在有 WriteTo 方法,因此它也實現了 io.WriterTo 介面。
  • crypto/hmac 有一個新函數,Equal,來比較兩個 MAC。
  • crypto/x509 包現在支援 PEM 塊(執行個體參閱 DecryptPEMBlock),以及一個新的函數 ParseECPrivateKey 用來解析橢圓曲線私密金鑰。
  • database/sql 包在 DB 類型上有了新的 Ping 方法用於檢測串連的健康情況。
  • database/sql/driver 有了一個新的 Queryer 介面,這樣 Conn 可以通過實現該介面對效能做一些改進。
  • encoding/json 包的 Decoder 有了新方法 Buffered,以提供訪問在其緩衝內剩餘資料的功能,同樣新方法 UseNumber 會將一個值解碼為其實是字串的新類型 Number,而不是一個 float64。
  • encoding/xml 包有了一個新函數 EscapeText,用於輸出 escape 過的 XML,Encoder 的方法 Inden 則專門用於輸出帶縮排的格式。
  • 在 go/ast 包中,新類型 CommentMap 和其關聯的方法使得從 Go 程式中分離和處理注釋變得更加容易。
  • 在 go/doc 包中,解析器現在可以更好的跟蹤一些如 TODO 這樣的標識,godoc 命令可以根據 -notes 參數選擇過濾或呈現這些資訊。
  • 一個新的包,go/format,為程式提供了更加方便的方式來獲得 gofmt 的格式化的能力。它有兩個函數,Node 用來格式化 Go 的解析 Node,而 Source 用來格式化 Go 的原始碼。
  • html/template 包中沒有文檔並且只部分實現的“noescape”特性被移除;那些依賴它的程式會被破壞。
  • io 包現在將 io.ByteWriter 介面匯出,用以滿足一次寫一個位元組這樣的常見功能。
  • log/syslog 包現在更好的提供了系統特定的日誌功能。
  • math/big 包的 Int 類型現在有了方法 MarshalJSON 和 UnmarshalJSON 用以轉換到或從 JSON 格式轉換。同樣,Int 現在可以通過 Uint64 和 SetUint64 直接轉換到 uint64 或從 uint64 轉換,而 Rat 通過 Float64 and SetFloat64.
  • mime/multipart 包的 Writer 有了新的方法,SetBoundary 用來定義包輸出的邊界分隔。
  • net 包的 ListenUnixgram 函數修改了傳回值的類型:現在它返回 UnixConn 而不是 UDPConn,這明顯是 Go 1.0 的一個錯誤。因此這個 API 的變更修複了一個 bug,這符合 Go 1 的相容性規則。
  • net 包包含了一個新函數,DialOpt,為 Dial 增加選項。每個選項都由新的介面 DialOption 體現。新的函數 Deadline、Timeout、Network 和 LocalAddress 然會一個 DialOption。
  • net 增加了帶地區驗證的本地 IPv6 地址的支援,如 fe80::1%lo0。地址結構體 IPAddr、UDPAddr 和 TCPAddr 將地區資訊記錄在一個新的欄位裡,那些需要字串格式作為地址的函數,例如 Dial、ResolveIPAddr、ResolveUDPAddr 和 ResolveTCPAddr 現在接受帶地區驗證的格式。
  • net 包添加了 LookupNS 作為解析函數。LookupNS 根據主機名稱返回一個 NS records 。
  • net 包向 IPConnReadMsgIP 和 WriteMsgIP)和 UDPConnReadMsgUDP 和 WriteMsgUDP)加了指定協議的讀寫方法。還有個 PacketConn 的特別版本的 ReadFrom 和 WriteTo 方法,提供了訪問資料包的帶外資料的能力。
  • net 為 UnixConn 添加了方法以便半關閉串連(CloseRead 和 CloseWrite),這與 TCPConn 的已有方法匹配。
  • net/http 包包含了若干新增。ParseTime 解析一個時間字串,會嘗試若干種常見的 HTTP 時間格式。Request 的 PostFormValue 方法與 FormValue 類似,不過忽略了 URL 參數。CloseNotifier 介面提供了伺服器端處理常式發現用戶端中斷連線的一種機制。ServeMux 類型現在有了 Handler 方法來訪問 Handler 的路徑而不需要執行它。Transport 現在可以通過 CancelRequest 取消一個進行中的請求。最後, 當 Response.Body 在完全被處理之前被關閉的話,Transport 現在會對關閉 TCP 串連保持更樂觀的態度。
  • 新的 net/http/cookiejar 包提供了基礎的管理 HTTP cookie 的功能。
  • net/mail 包有了兩個新函數,ParseAddress 和 ParseAddressList,來解析 RFC 5322 格式化的地址到 Address 結構體。
  • net/smtp 包的 Client 類型有了一個新的方法,Hello,用於向伺服器發送 HELO 或 EHLO 訊息。
  • net/textproto 有兩個新函數,TrimBytes 和 TrimString,用來僅在 ASCII 下進行前後空符的切除。
  • 新方法 os.FileMode.IsRegular 讓瞭解一個檔案是否是普通檔案變得更加簡單。
  • image/jpeg 現在可以讀取預先載入 JPEG 檔案,並且處理某些二次取樣配置資訊。
  • regexp 包現在通過 Regexp.Longest 可以支援 Unix 原生的最左最長相符,而 Regexp.Split 使用Regex定義的分離器將字串分解成組的。
  • runtime/debug 有三個關於記憶體使用量的新函數。FreeOSMemory 函數觸發記憶體回收,並嘗試將未使用的記憶體退回作業系統;ReadGCStats 獲得控制器的統計資訊;而 SetGCPercent 提供了一個可程式化的途徑來控制控制器執行頻率,包括永遠禁止其執行。
  • sort 包有一個新函數,Reverse。作為調用 sort.Sort 的參數的包裹,通過調用 Reverse 可以讓排序結果反續。
  • strings 包有兩個新函數,TrimPrefix 和 TrimSuffix 含義不言而喻,還有 Reader.WriteTo 方法,因此 Reader 現在實現了 io.WriterTo 介面。
  • syscall 包的有許多更新,包括對每個支援的作業系統的系統調用進行加固。
  • testing 包現在可以在效能測試中使用 AllocsPerRun 函數和 BenchmarkResult 的 AllocsPerOp 方法自動產生記憶體配置統計。還有 Verbose 函數來檢測 -v 的命令列參數狀態,和 testing.B 和 testing.T 的新方法 Skip 來簡單跳過一些不必要的測試。
  • 在 text/template 和 html/template 包中,模板現在可以用圓括弧來對字元序列分組,這簡化了建立複雜的字元序列的過程。TODO:連結到一個執行個體。同時,作為新的解析器的一部分,Node 介面有兩個方法用來提供更好的錯誤報表。這同樣遵循 Go 1 相容性規則,由於這個介面被明確期望只有 text/template 和 html/template 包使用,而其安全機制保證了這點,所以應當沒有代碼會受到影響。
  • 在 unicode/utf8 包中,新函數 ValidRune 報告了一個 rune 是否是一個合法的 Unicode 編碼值。為了確保合法,rune 的值必須在範圍內,且不能為半個代用符。
  • unicode 包的實現被更新到 Unicode 7.2.0 版本。

————翻譯分隔線————
時運不濟,幾片去痛片壓制下才勉強撐了幾天。只是看來去痛片解決不了發燒問題。回到家被強制休息了……
拖到今天才翻譯完,而且我相信,品質一定很差很差很差……
大家自己看吧!有問題給我留言,我休眠了。
如果明天早上我沒回來,請諸位向 God of Gopher 禮拜,我一定是去了那美麗的地方。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.