您好,登錄后才能下訂單哦!
這篇文章主要講解了“Go 1.1有哪些新特性”,文中的講解內容簡單清晰,易于學習與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學習“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 0xffffffff i := int(x) // i is -1 on 32-bit systems, 0xffffffff on 64-bit fmt.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/quxx can'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/quxx package 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/quxx warning: GOPATH set to GOROOT (/home/User/go) has no effect package 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 包向 IPConn(ReadMsgIP 和 WriteMsgIP)和 UDPConn(ReadMsgUDP 和 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 使用正則表達式定義的分離器將字符串分解成組的。
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 版本。
感謝各位的閱讀,以上就是“Go 1.1有哪些新特性”的內容了,經過本文的學習后,相信大家對Go 1.1有哪些新特性這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是億速云,小編將為大家推送更多相關知識點的文章,歡迎關注!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。