亚洲国产成人精品久久_欧美日韩国产综合一区二区_亚洲精品理论电影_色综合久久中文字幕

首頁 » 早鳥快報 » 咨詢 » 正文

解讀Go語言的2019_Go語言不行了嗎?

放大字體  縮小字體 發布日期:2019-12-29  來源:來自互聯網  作者:來自互聯網  瀏覽次數:246
導讀

Go 語言目前所擅長的領域仍然在服務端的 Web 系統、API 網關、中間件、緩存系統,以及數據庫、容器技術和云計算等方面。由于 Go 語言在軟件的開發、構建、測試、部署等方面做得都非常好,所以它對于企…

作者丨郝林

策劃丨張曉楠

因那些科幻電影而讓大家有著無限憧憬的 2020 年已來!然而,我們卻依然處在人工的智能階段。時下如火如荼的人工智能與真正的智能之間還有著相當長的一段距離。作為緊跟時代步伐的軟件開發者,我們還是應該務實一些,多做一些腳踏實地的事情,尤其是在構建底層的基礎設施方面。而 Go 語言正是我們做這類事情時所需要的強大工具。本文是 InfoQ “解讀 2019 ”年終技術盤點系列文章之一。

趨勢:排名 15,仍處主流之列

從 TIOBE Index 來看,Go 語言最近在全球的熱度似乎有所下滑。不過,如果看總體排名的話,截止到 2019 年的 12 月,Go 語言依然排在第 15 位,仍處于主流之列。雖然中途存在一些起落,但總體上還是與去年同期持平的。

圖 1:TIOBE Index 之 Go 語言(2019 年 12 月)

圖 2:TIOBE Index(2019 年 12 月)

簡單來講,TIOBE Index 在給這些編程語言排序的時候,依據的是它們在幾個主流搜索或媒體平臺上的相關展示數。這些平臺包括 Google、Baidu、Yahoo、CSDN、Bing、Amazon、Hao123 等等。所以說,還是比較客觀的。

從 Google Trends 來看,Go 語言在全球的趨勢是穩中有升的。去年此時,Go 語言熱度還是 82,而現在它已經慢慢地升到了 90。

圖 3:Google Trends 之 Go 語言趨勢(2019 年 12 月)

如果我們把目光聚焦在國內,那么就可以看到,北京依然是 Go 語言使用者的主要聚集地,沒有之一。但不得不說,深圳、杭州、成都、上海、廣州等城市也有很多優秀的 Go 程序開發者。

圖 4:Google Trends 之 Go 語言熱度(2019 年 12 月)

從我的觀察來看,Go 語言已經過了第二波快速推廣期,并且進入了穩定發展期,起碼在國內是這樣。已經在使用 Go 語言的技術團隊逐漸開始專注于埋頭寫代碼,而剛開始使用 Go 語言的團隊也沒有進行大肆的宣傳。Go 語言已經悄悄地變成了我們的家常便飯。

領域:有擅長也有短板

Go 語言目前所擅長的領域仍然在服務端的 Web 系統、API 網關、中間件、緩存系統,以及數據庫、容器技術和云計算等方面。在這些方面,我們有非常多的框架可以選擇。其中最受歡迎的框架和軟件如下:

Web 框架:Gin 、 Beego 、 Echo 等。

微服務框架:go-kit 、 go-micro 等。

數據庫連接庫:go-sql-driver/mysql 、 go-redis/redis 、 mongo-go-driver 、 go-elasticsearch ,以及 gorm 、 xorm 等。

中間件軟件:etcd 、 Consul 、 NSQ 、 Caddy 等。

數據庫軟件:TiDB 、 Cockroach 、 InfluxDB 、 Cayley 等。

數據爬取軟件:Pholcus 、 Colly 等。

此外,還有大名鼎鼎的 Kubernetes 及其生態圈中的那些知名項目。更多的優秀 Go 語言項目可以參考我在極客時間專欄《Go 語言核心 36 講》中的思維導圖。如果你只是想知道國內的 Go 程序開發者都發布了哪些開源項目,那么也可以參考我發起的 awesome-go-China 項目。

另一方面,對于那些面向企業的管理系統,Go 語言更是不在話下。在最近發布的一份 2019 年十大企業級編程語言榜單中,Go 語言排在第 4 位。在它前面的只有 Javascript、Java 和 Python 這三門歷史悠久的編程語言。由于 Go 語言在軟件的開發、構建、測試、部署等方面做得都非常好,所以它對于企業級軟件研發來說也有很強的競爭力。

當然了,Go 語言明顯不擅長的領域也有幾個。雖然 Go 語言已經對一些移動端和嵌入式設備有所支持,但終歸還未成熟。況且,在這些方面至今還沒有出現過殺手級別的應用項目。如果非要找出來一個的話,我覺得只有 Gobot 項目才夠資格。另外,Go 語言在科學計算、數據科學、機器學習等領域的介入依舊非常少。對于作為前沿中的前沿的人工智能,Go 語言也少有涉足。我目前只知道有一個用于科學計算的 Gonum 項目發展得還算可以。不過,不要忘了,人工智能以及將來會與之相伴的物聯網依然需要服務端軟件、需要云計算。而 Go 語言早已在這里站穩了腳跟。

最后,我們再來說一說區塊鏈。區塊鏈的名聲源自數字貨幣。而數字貨幣之亂從未停息過。所以,區塊鏈在人們的心中早已不那么純潔了。恐怕它已經成為了計算機軟件領域的哈姆雷特。幾乎每一個知道區塊鏈的人在談論到它的時候心里都會描繪著不同的情景。盡管如此,一些有情懷的廠商正在使用區塊鏈技術做著造福大眾的事情,比如:支付寶、輕松籌等等。不得不說,Go 語言是區塊鏈頂級技術的有力競爭者,而且它也早已成為了區塊鏈領域中必不可少的技術技能。我們在這方面可以選擇的平臺或框架已經有不少了,如 Go Ethereum 、 Fabric 、 Cosmos 、 Eris 等。另外,還有一些不錯的基于區塊鏈技術的數據存儲項目,如 CovenantSQL 、 Sia 等。

變化:趨于穩定

在 2019 年,Go 語言的版本已經更新到了 1.13。然而,由于它在語言規范方面已經趨于穩定,所以只有一些小幅變化。其中,與我們最貼近的就是它在數值字面量方面的改進。

數值字面量

Go 語言的數值字面量現在可以通過一些前綴來表明不同的制式了。前綴 0b 和 0o 分別可以用于表示二進制整數和八進制整數,比如 0b1110 代表整數 14,0o770 代表整數 504,等等。而前綴 0x 是之前就有的,它可以用于表示十六進制整數。不過,它現在還可以表示十六進制的浮點數,比如 0x10p+1 代表 32.000000。這實際上屬于科學記數法。其中的 p+1 是這個浮點數的指數部分。我們可以在 p 的后面追加正負號和代表指數的十進制整數,以表明需要在前一個部分的基礎上再乘以 2 的幾次方。因此,p+1 表示需要再乘以 2 的 1 次方。又由于 0x10 代表整數 16,所以 0x10p+1 表示的就是浮點數 32.000000。同理,0x10p+2 代表浮點數 64.000000,而 0x10p-1 代表浮點數 8.000000,以此類推。不僅如此,以上的這些表示法現在也都可以被用來表示虛數,如 1.e+3i 等。

除此之外,Go 語言終于開始支持數字分隔符了!這個改進點雖然小,但卻是一個千呼萬全的優化。它其實是一個語法糖,讓我們可以在一長串的數字之間插入分隔符“_“,以便使人們更加容易地讀出或寫入這些數字。更贊的是,這個分隔符被插入到哪里都是可以的。比如,對于整數 123456789,我們寫成 123_456_789 或者 1_2345_6789 都是沒有問題的。甚至,我們還可以在上述的各種表示法中運用這個分隔符,如 0x67_89 和 3.14_15,等等。別擔心,雖然這樣的數值字面量都包含了這么一個明顯的非數字字符,但是卻不會影響到 Go 語言對它們的解析。Go 語言會在適當的時候忽略掉其中的分隔符。

這些在數值字面量方面的改進可以讓 Go 語言更好的融合到新領域的軟件開發當中。比如,我們在開發財務軟件和金融系統的時候就很需要這些特性。一方面,這樣的字面量可以大大地降低我們在編碼時出錯的概率。而另一方面,它們還可以明顯地提高程序的可讀性,從而減少維護者的認知成本和工作量。

移位操作

Go 語言中的移位操作可以對處在移位運算符左側的數值(或稱操作數)進行二進制移位,移位的具體次數會由處在移位運算符右側的數值(或稱移位計數)決定。下面是一些簡單的例子:

operand1 := -2count1 := 1fmt.Printf("%d fmt.Printf("%d >> %d: %d\n", operand1, count1, operand1>>count1)

輸出內容:

-2 -2 >> 1 // -1

在 Go 1.13 發布之前,移位計數的類型必須是某個無符號的整數類型。對于 Go 的語言規范和具體實現來說,這樣做確實可以減少一定的工作量。但是,對于應用程序的開發者而言,這里卻隱藏著無法忽略的的工作成本。當我們想把一個整數作為移位計數的時候,必須要保證它的類型是無符號的。如果它不是,那么我們就不得不進行某種手動的類型轉換,否則程序在被編譯時就會出錯。即使這個整數確實是一個正數,也是如此。我相信大多數的程序開發者都會覺得這很麻煩,而且沒有必要。

然而,更重要的還不是這個工作量的問題。如果我們在將要進行移位操作的時候強行地把某個負數轉換為無符號整數類型的值,那么就很有可能遇到非預期的情況,從而在程序中埋下一個非常不易察覺和定位的 BUG。示例如下:

operand2 := -1count2 := -8count2u := uint8(count2)fmt.Printf("%d

輸出內容:

-1

顯然,把 -1 向左移位 248 次很可能并不是我們想要的。

鑒于上述原因,Go 語言團隊在 Go 1.13 中修正了這個問題。移位計數不再被要求必須是無符號整數類型的值了,只要是整數值就可以。我們可以想象一下,當設定的移位計數小于零時,如果 Go 程序會立即拋出一個運行時恐慌(panic),而不是悄悄地吞沒了 BUG 并改變了我們的意圖,那么我們是不是會更開心一些呢?因為程序中的 BUG 被更早地暴露了出來,而且 BUG 的定位和修復還都很容易。

順便說一下,針對移位操作的這一改變使得 Go 語言的一些行為更加一致了。比如,雖然 len 函數一定會把某個正整數作為其結果值,但它的結果類型卻是 int。又比如,我們在創建一個切片的時候可以使用 make 函數。雖然它的第二個參數值必須是某個正整數,但是這個參數的類型卻也是 int。之所以它們沒有通過類型來嚴格地約束被傳遞的值,正是因為那可能會催生出一些額外的類型轉換代碼。我們很難保證對于任何值的類型轉換都一定會產生符合預期的結果。況且,這還很可能會掩蓋掉一些本來應該暴露出來的錯誤。

當然了,這一改變也帶來了一個新的問題,那就是我們需要自行保證移位計數為正數。不過,這并不困難,也是我們應該做的。而且,當移位計數是由一個常量代表的時候,Go 語言的編譯器會先對它進行檢查。如果這個常量不是一個正整數,那么程序是不會通過編譯的。因此,這個新問題所帶來的影響就基本上可以忽略不計了。

字典的打印

我們都知道,基本上所有的編程語言中的常規字典(或者說映射)都屬于無序的容器。也就是說,它們的實例都不會對其包含的鍵值對的先后順序作出任何的保證。這就意味著,雖然我們可以通過某個鍵快速地從字典中獲取對應的值,但不能指望通過迭代快速地得到這個鍵值對。因為我們不知道這個鍵值對會在第幾次迭代時被返回。字典的這一特性是由它的內部結構決定的。Go 語言中的字典也是如此。

這就導致了一個問題。我們很難有效地觀察字典的即時狀態。由于字典迭代的無序性,通過遍歷字典進行觀察就變成了一種很糟糕的方式。尤其是當字典包含了成千上萬個鍵值對的時候,我們想用肉眼去發現前后兩個狀態的異同幾乎是不可能的。然而,我們若要用程序去自動地識別它們的不同,其效率顯然也不會太高。下面舉例說明。

我們現在有一個 map[int]string 類型的字典 map1,并且已經以從小到大的順序放入了一些鍵值對。其中的鍵都是一些正整數,而與之對應的值都是鍵的字符串形式,比如,整數值 1 與字符串值 “1” 會共同組成一個鍵值對。如此一來,下面的代碼就會遍歷這個字典并依據迭代的次序打印出其中的各個鍵值對:

fmt.Printf("Map: [\n ")for k, v := range map1 { fmt.Printf("%d:%s ", k, v)}fmt.Println("\n]")

輸出內容:

Map: [ 3:3 4:4 7:7 5:5 6:6 8:8 9:9 0:0 1:1 2:2]

我們可以看到,打印出來的內容體現的是“亂序”的鍵值對。正因為如此,我們無法在這里用比較字符串值的方式來比較字典的多個即時狀態。我相信,大多數寫過 Go 程序測試代碼的 gopher 們都為此苦惱過。

好消息是,從 2019 年的 2 月份開始,我們終于對此擁有了一種有效的手段。在 Go 1.12 中,官方團隊對 fmt 包中的一系列打印函數進行了優化。這使得它們將會依據鍵的大小去依次地打印字典中的鍵值對。相應代碼如下:

fmt.Printf("Map: %v\n", map1)

輸出內容:

Map: map[0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 8:8 9:9]

這個結果就不用我多解釋了吧。這些鍵值對是以升序排列的。不過要注意,字典在被迭代的時候依然會以“亂序”的方式吐出一個個鍵值對。所以,前一種打印方式所產生的結果依舊。而有序的鍵值對只會體現在上面這種整體打印的情況下。

讓我們再稍微深入一點。在整體打印的過程中,對于不同類型的鍵,打印函數的比較方式也會有所不同。具體如下:

先來說基本類型的鍵。對于整數值、浮點數值和字符串值,打印函數會利用標準的比較操作進行排序。浮點數中的 NaN 會比其他的浮點數值更小。對于復數值,打印函數會先比較實部再比較虛部。更具體的比較方式同上。而對于布爾值來說,false 肯定是比 true 更小的。

對于指針值和通道值,打印函數會去比較它們在內存中的地址。請注意,這里所說的指針值特指通過取址操作符獲得的指針值,并不是 uintptr 類型或者 unsafe.Pointer 類型的值。對于 uintptr 類型的鍵,打印函數會把它們當作整數值去比較。而對于 unsafe.Pointer 類型的鍵,打印函數根本就無法比較它們。請記住,對一個鍵類型為 unsafe.Pointer 的字典進行整體打印會引發一個運行時恐慌。

對于結構體值和數組值,打印函數會逐一地比較其中的字段值或元素值,直到能夠判斷出誰大誰小為止。

對于接口類型的值,打印函數會先利用反射識別出它們的實際類型,然后再依據上面的規則進行比較。

最后,如果字典的鍵允許為 nil,那么 nil 一定是最小的。

這些比較規則很簡單,你肯定花費不了多少時間就可以記住它們。不過,即使你懶得去了解這些細則,也不會妨礙你從中受益。示例代碼如下:

// 生成第一個快照。snapshot1 := fmt.Sprint(map1)fmt.Printf("Snapshot 1: %s\n", snapshot1)// 修改 map1:增加一些新的鍵值對。for i := max + 1; i key1 := i map1[key1] = genValueBy(key1)}// 修改 map1:改動一個已有的鍵值對。map1[max-5] = "0"http:// 生成第二個快照。snapshot2 := fmt.Sprint(map1)fmt.Printf("Snapshot 2: %s\n", snapshot2)// 直接比較兩個快照。fmt.Printf("Snapshot 2 > Snapshot 1 ? %v\n", snapshot2 > snapshot1)

輸出內容:

Snapshot 1: map[0:0 1:1 2:2 3:3 4:4 5:5 6:6 7:7 8:8 9:9]Snapshot 2: map[0:0 1:1 2:2 3:3 4:4 5:0 6:6 7:7 8:8 9:9 11:11 12:12 13:13]Snapshot 2 > Snapshot 1 ? false

面對這樣整齊的輸出,我們即使僅憑肉眼也可以輕易地找出兩個快照的不同,不是嗎?更何況,這樣的輸出對于測試或監測程序來說也是非常友好的。

錯誤的包裝和追溯

Go 語言中的 error 值看起來很普通。它們的內部結構一般都非常的簡單,最多也只是會包含一些有助于定位問題的字符串信息罷了。這讓我們可以輕易地對這些 error 值進行判斷和比較。

不過,這樣的 error 值也有一個很明顯的缺點,那就是不便追溯。一旦程序出錯了,我們總是想第一時間知道問題到底出在了哪里。即使 error 值包含了一些有用的字符串形式的錯誤信息,我們也往往只能憑借對程序的熟悉程度和以往的程序調試經驗去推測出錯的原因和具體位置。

不只是這樣,當我們得到一個 error 值的時候,它有可能代表的并不是那個原發的錯誤,而是由程序內部的錯誤處理代碼轉發出來的另一個新生成的 error 值。如果那段錯誤處理代碼編寫得當的話,這個新生成的 error 值應該會包含一些描述原發錯誤的信息。但是,它需要包含多少原發錯誤信息,以及它包含的信息是否真正有用,是沒有一個統一的標準的,基本上全憑那段代碼的編寫者說了算。這種方式顯然太松散了,對于代碼質量的管理是非常不利的。

也正因為如此,一些 Go 程序的優秀開發者已經在編寫更好的錯誤處理包了。目前業界公認的比較好用的代碼包有 github/pkg/errors 和 gopkg.in/errgo.v2,等等。

由于開發者們對更好的錯誤處理標準的渴望以及普遍存在的呼聲,Go 語言團隊在大約一年以前開始考慮對現有的 errors 包進行改進。終于,在 Go 1.13 中,新的錯誤處理機制開始被融入到已有的 errors 包里了。下面,我們就來一起看一看這個博眾家之所長的新機制是怎樣的。

首先,我們在一個 error 值中包含另一個 error 值的做法終于得到了官方的支持。并且,我們現在可以使用一種標準的方式從前者之中拿出后者。例如,我編寫了兩個錯誤類型:

// DetailedError 是一個有錯誤詳情的錯誤類型。type DetailedError struct { msg string}

// Error 會返回 error 的信息。func (de DetailedError) Error() string { return de.msg}

// WrappedError 是一個可包裝其他錯誤的錯誤類型。type WrappedError struct { msg string inner error}

// Error 會返回 error 的信息。func (we WrappedError) Error() string { return we.msg}

// Unwrap 會返回被包裝的 error 值。func (we WrappedError) Unwrap() error { return we.inne}

我讓 DetailedError 類型擁有 Error() string 方法,是為了讓它實現 error 接口。Go 程序員肯定都知道這一點。然而,錯誤類型 WrappedError 不只有 Error() string 方法,還有 Unwrap() error 方法。后者是為了讓 errors.Unwrap 函數能夠支持 WrappedError 類型的值。

errors.Unwrap 函數就是我在前面提到的那個標準的方式。它可以從一個錯誤值中取出另一個錯誤值。但前提是,前者必須擁有 Unwrap() error 方法,并且該方法一定會返回該錯誤值包含的那個錯誤值。

基于上面的類型聲明,下面的代碼會打印出如我們所愿的內容:

err1_1 := errors.New("unsupported operation")err1_2 := WrappedError{ msg: "operation failed", inner: err1_1,}fmt.Printf("Message(outer error): %v\n", err1_2)fmt.Printf("Message(inner error): %v\n\n", errors.Unwrap(err1_2))

輸出內容:

Message(outer error): operation failedMessage(inner error): unsupported operation

我不知道你有沒有發現,這使得我們可以生成一條任意長度的錯誤鏈。持有這條錯誤鏈的程序可以通過 errors.Unwrap 函數從近端的(或者說最外層的)錯誤值開始依次地獲取到它包含的所有錯誤值,直到取出最遠端的(或者最內層的)那個錯誤值為止。如此一來,我們就可以一層一層地包裝錯誤值以反映出錯誤發生時的上下文狀態。另一方面,拿到這樣的錯誤值的程序也就有機會知道引發錯誤的根本原因是什么了。

當然了,我們讓錯誤類型擁有 Unwrap() error 方法不只有這一點好處。這樣做也會讓 errors.Is 函數和 errors.As 函數開始支持此類型。

errors.Is 函數的簽名是 Is(err, target error) bool。它的功能是從 err 以及它直接或間接包含的錯誤值中尋找等于 target 的值。它會沿著錯誤鏈由外及內地對每一個錯誤值進行判斷。一旦找到了相等的錯誤值,它就會返回 true。如果在遍歷完整條錯誤鏈之后仍未找到與 target 相等的錯誤值,那么它就會返回 false。

errors.As 函數的尋找路徑與 errors.Is 函數是一樣的。只不過,它尋找的是在類型上與目標一致的錯誤值。從該函數的簽名 As(err error, target interface{}) bool 我們就可以了解到,參數 target 雖然會代表某個值,但是這個值的類型才是判斷的真正依據。當我們有如下的兩個變量:

err2_1 := DetailedError{ msg: "unsupported operation",}err2_2 := WrappedError{ msg: "operation failed", inner: err2_1,}

那么,調用表達式 errors.Is(err2_2, err2_1) 和 errors.As(err2_2, &DetailedError{}) 返回的值就肯定都會是 true。注意,errors.As 函數的第二個參數值必須是某個錯誤值的指針值,而不能是錯誤值本身。否則將會引發一個運行時恐慌。

然而,就算已經落實了這些改進,Go 1.13 中的 errors 代碼包也依然處于一個“改進中”的狀態。這主要是為了做到循序漸進和保證向后兼容。充分落實了新錯誤處理機制的代碼實際上在 golang.org/x/xerrors 包中。這個代碼包在 GitHub 上也有托管,地址是:

https://github/golang/xerrors 。

利用這個代碼包,我們可以很方便地讓現有的打印函數逐層地打印出一條錯誤鏈中的所有錯誤信息。不過,這就需要我們為錯誤類型添加更多的方法了。代碼如下:

// FormattedError 是可暴露內部錯誤信息的錯誤類型。type FormattedError struct { msg string inner error}

// Error 會返回 error 的信息。func (fe FormattedError) Error() string { return fe.msg}

// Unwrap 會返回被包裝的 error 值。func (fe FormattedError) Unwrap() error { return fe.inner}

// Format 會打印格式化后的錯誤值。func (fe FormattedError) Format(f fmt.State, c rune) { xerrors.FormatError(fe, f, c)}

// FormatError 會返回錯誤鏈中的下一個錯誤值。func (fe FormattedError) FormatError(p xerrors.Printer) (next error) { p.Print(fe.Error()) return fe.Unwrap()}

錯誤類型 FormattedError 不但擁有 Error 方法和 Unwrap 方法,還擁有 Format 方法和 FormatError 方法。其中,Format 方法是現有的錯誤處理機制中的一部分,標準的打印函數在打印一個錯誤值的時候會試圖調用該值的 Format 方法以實現打印內容的自定義。

可以看到,FormattedError 類型的 Format 方法中只有一行代碼,即:xerrors.FormatError(fe, f, c)。這行代碼很關鍵。因為 xerrors.FormatError 函數會在適當的時候調用參數 fe 及其代表的錯誤鏈中的所有錯誤值的 FormatError 方法(如果有的話)。

顯而易見, FormatError 方法是 xerrors 包代表的新錯誤處理機制所特有的。它應有的功能是,在打印當前的錯誤值之后返回該值包含的那個錯誤值。這樣的話,只要這些錯誤值都擁有 FormatError 方法,再加上調用了 xerrors.FormatError 函數的 Format 方法,那么即使是一個普通的打印函數也可以打印出整條錯誤鏈中的所有錯誤信息。請看下面的示例:

err3_1 := DetailedError{ msg: "unsupported operation",}err3_2 := WrappedError{ msg: "operation failed", inner: err3_1,}err3_3 := FormattedError{ msg: "operation error", inner: err3_2,}fmt.Printf("Error: %v\n", err3_3)

最后一條打印語句會導致如下內容的輸出:

Error: operation error: operation failed

請注意,之所以這行輸出內容中沒有“unsupported operation”,是因為 WrappedError 類型并沒有像 FormattedError 類型那樣的 Format 方法和 FormatError 方法。

由于篇幅原因,關于 xerrors 包的更多情況我就不多說了。我們其實完全可以使用 xerrors 包而不用標準庫中的 errors 包來創建和處理錯誤值。這樣就可以享有新錯誤處理機制所帶來的全部好處了。

其他

除了上述幾個比較重要的改進之外,官方團隊在這一年還對 Go 語言做了很多的更新和優化。其中,值得我們特別注意的有:

Modules 基本上已經轉正了。環境變量 GO111MODULE 的默認值已是 auto。并且,即使代碼處在 GOPATH/src 目錄下,Modules 機制也會奏效。這就意味著,go 命令在任何情況下都會具有模塊感知能力,從而大大地簡化了舊代碼遷移的工作量。

GOPROXY 可以有多個了。環境變量 GOPROXY 的值現在可以是由英文逗號分割的多個地址了,如:GOPROXY=https://goproxy, https://goproxy.io ,direct 。Go 的命令行工具在從網絡上獲取代碼包的時候會依次嘗試從這些地址下載。

TLS 1.3 已成為缺省配置。在代碼包 crypto/tls 中,TLS 1.3 已經是缺省的配置了。不過,如果你想繼續使用 TLS 1.2,那么可以讓環境變量 GODEBUG 的值中包含 tls13=0 。當然了,我是不建議這么做的。而且,這種倒退的選擇將在 Go 1.14 中被丟棄。

Binary-only packages 以后將不會再受到支持。Go 1.13 將是支持它的最后一個版本。我們也可以稱這種包為純二進制包。如果你還不知道這是什么,那么以后也不用再去了解了。但倘若你正在使用這種包,請盡快作出相應的替換和更改。

代碼運行的性能又有大幅提升。這包括:defer 語句的性能提高了 30%;sync.once 類型的 Do 方法快了一倍,互斥鎖和讀寫鎖的方法也提速了 10%。Go 運行時中的計時器和 deadline 檢查代碼更快了,這使得維護網絡鏈接的操作更加高效,并且在多 CPU 的計算機上擁有更好的可擴展性。

至此,我們已經闡述了 Go 語言本身在 2019 年最主要的那些變化。希望這些內容能夠對你使用新版本的 Go 語言有所幫助。對于這部分所展示的所有代碼,我已經發布到了 GitHub 上,鏈接地址:

https://github/hyper0x/go2019

展望:Go 2 會不負眾望

在我撰寫這篇文章的時候,Go 1.14 的開發周期其實早已開始了,甚至其 beta 版本都已經發布了。從目前公開的資料來看,新版本的改進主要還是集中在工具鏈的易用性和功能性優化、Modules 機制(與早先的 vendor 等機制)的進一步融合、運行時系統的性能優化、測試包的易用性優化、網絡安全協議實現的更替等方面。此外,還有很多的問題修復和小幅改進。

當前,除了主打的服務端之外,Go 語言還在向著大前端(主要是 WebAssembly)的方向發力。而早先被納入的移動端在 2019 年倒是沒有什么大的動作,主要還是對最新版本的 iOS 和 Android 提供了支持。我們當然是希望 Go 語言能在全端都有良好的發展。但這終歸是要分清主次的。Go 語言的著力點仍然以 Web 服務程序為中心。我想,在廣義的 Go 語言技術社區仍需進一步開放、官方團隊的時間和精力依然非常有限的情況下,這也算是一個很好的策略了。

按照原計劃,Go 2 應該會以一種比較平滑的方式出現。關于這一點,我們從官方團隊對 errors 代碼包的更新方式上就能夠看得出來。Go 2 草案中提到的一些特性在今后的一段時間里可能會陸續的以標準庫更新或者新擴展庫的形式融入到 Go 1 當中,就像 golang.org/x/xerrors 包那樣。如此一來,使用 Go 1 的大部分開發者就都可以提前享受到一些新特性帶來的好處了。不得不說,Go 語言在向后兼容方面做得是相當不錯的。

大家肯定也能感覺得出來,Go 1 在語言特性和標準庫方面已經相當穩定了。我認為,除了逐漸融入 Go 2 的新特性,Go 1 應該不會再有大的變化了,進一步的優化、改進和完善應該是官方團隊在短期內的主要工作。

就我個人而言,雖然 Go 程序在性能方面早已甩掉 Python 好幾條街,也早就超過了 Java,但我依然希望它能夠進一步地把性能優勢發揮到極致,尤其是并發程序方面的性能。另外,我也希望 Go 語言的 Modules 機制、錯誤處理機制,以及各種監測和調試工具都能夠更上一層樓、越來越好用。

由于 Go 語言屬于強類型的編譯型編程語言,所以它在語法的自由度和上手的便捷度方面還是稍顯遜色的。當然了,這件事情有利有弊。每門編程語言都會有自己的權衡。對于團隊級別的軟件開發,尤其是中大規模團隊級別的軟件開發來說,嚴謹的語法是非常有益的。不論怎樣,開發者們(包括我)都希望能用更少的代碼完成更多的工作,同時程序還要更易于維護,并且保持優良的性能(要求實在是很多啊)。我希望也相信 Go 語言會繼續以自己的方式朝著這方面努力和發展。

我斷定,在今后的幾年中,云計算和大數據仍然會是非常有潛力和有前途的領域。隨著 5G 的到來,它們也會為人工智能和物聯網提供強有力的支撐。Go 語言目前在云計算領域非常的受歡迎。不過,它在大數據領域至今還沒有嶄露頭角。起碼還沒有一個殺手級別的應用程序出來。我倒是很盼望能有這樣的程序問世,但是這顯然不太容易。因為,大數據的生態系統在很早以前就被 Java 平臺下的技術霸占了。

最后,雖然 Go 語言肯定是 Google 公司的 Go 語言,但是 Go 語言團隊現在顯然已經更加的開放了。他們在一步一步地擁抱技術社區,聽取社區的意見和建議、參考和采納社區的想法和技術實現。因此,以這樣的態勢,我堅信 Go 語言的發展會越來越好,同時對普通的開發者也會越來越友好。相對于 Go 1 的趨于穩定,我相信將在未來發布的 Go 2 絕對會不負眾望,也會足夠的驚艷。希望到時候會有更多的愛好者來使用這門優秀的編程語言。

InfoQ 讀者交流群上線啦!各位小伙伴可以掃描下方二維碼,添加 InfoQ 小助手,回復關鍵字“進群”申請入群。大家可以和 InfoQ 讀者一起暢所欲言,和編輯們零距離接觸,超值的技術禮包等你領取,還有超值活動等你參加,快來加入我們吧!

大會推薦

QCon 北京 2020 全新起航,來跟業界大牛關注 23+ 技術領域中正在興起的技術和關鍵進展。目前大會 7 折報名最后一周,點擊【閱讀原文】或識別二維碼了解更多。有任何問題歡迎聯系票務小姐姐 Ring:17310043226(微信同號)

 
 
免責聲明
本文為會員免費發布,僅代表發布者個人觀點,本站未對其內容進行核實,請讀者僅做參考,如若文中涉及有違公德、觸犯法律的內容,一經發現,立即刪除,作者需自行承擔相應責任。涉及到版權或其他問題,請及時聯系我們刪除處理。
 
 
主站蜘蛛池模板: 国产精品久久久久999| 五月天综合婷婷| 国产精品入口免费视频一| 99久久国产综合精品五月天喷水| 久久久久久综合网天天| 国产精品免费成人| 久久国产精品久久久久久久久久| 三区精品视频观看| 91久久大香伊蕉在人线| 国产精品免费网站| 国产精品一香蕉国产线看观看| 欧美久久在线观看| 日本在线播放不卡| 视频一区在线免费观看| 91精品国产乱码久久久久久蜜臀| 国产精品自产拍高潮在线观看| 欧美中日韩在线| 日韩视频永久免费观看| 中文字幕欧美日韩一区二区三区| 国产精品毛片一区视频| 免费在线观看的毛片| 欧美亚洲一级片| 免费观看国产精品视频| 久久久久久久久久久久久久久久久久av | 日本丰满少妇黄大片在线观看| 中文字幕日韩一区二区三区不卡| 国产精品免费入口| 国产精品观看在线亚洲人成网| 国产美女久久精品香蕉69| 国产精品久久久久久久久免费| 国产精品美女网站| 91成人福利在线| 视频在线一区二区| 日韩精品欧美专区| 蜜臀精品一区二区| 国产在线精品一区| 国产精品久久久久久久久久东京| 国产精品自拍视频| 亚洲伊人久久大香线蕉av| 丝袜一区二区三区| 久久久久久国产精品|