1. Rob,你創建了 Google Go 這門語言。什麼是 Google Go?能簡明扼要的介紹一下 Google Go 嗎?#
我還是講講為什麼要創建這門語言吧,和你的問題稍有些不同。我在 Google 做了一個有關編程語言的系列講座,在 Youtube 上有,談及了我早期所寫的一個語言,叫做 Newsqueak,那是八十年代的事,非常早。在做講座期間,我開始思考為什麼 Newsqueak 中的一些想法在我現在以 C++ 為主的工作環境中無法使用。而且在 Google 我們經常要構建非常大的程序,光構建就要花很多時間,對依賴的管理也有問題,由於鏈接了本來並不需要的東西,二進制程序包變得很大,鏈接時間很長,編譯時間也很長,而且 C++ 的工作方式有點古老,其底層實際上 C,C++ 已經有三十年的歷史了,而 C 則更是有四十年了。用現今的硬件做計算,有很多新東西需要考慮:多核機器、網絡化、分佈式系統、雲計算等等。
2. Go 的主要特點是什麼?有什麼重要功能?#
對於大多數人來說,他們對 Go 的第一印象是該語言將並發性作為語言原語,這對我們處理分佈式計算和多核這類東西來說非常好、也非常重要。我猜許多人會認為 Go 是一門簡單無趣的語言,沒有什麼特別的東西,因為其構想看起來一目了然。但實際上不能用第一印象來判斷 Go。很多用過 Go 的人會發現它是一門非常高產而且有表現力的語言,能夠解決我們編寫這門語言時期望其所能解決的所有問題。
Go 的編譯過程很快,二進制程序包又比較小,它管理依賴的方式如同管理語言本身的東西一樣。這裡還有一個故事呢,但是在這裡就不再展開討論了,但是這門語言的並發性使其能夠以非常簡單的模式來處理非常複雜的操作及分佈式計算環境。我想最重要的功能可能就是並發性了,後面我們可以談談該語言的類型系統,其與 C++、Java 這類傳統面向對象類型系統的差異很大。
3. 在我們繼續話題之前,能否解釋一下為什麼 Go 編譯器能達到那麼快的編譯速度呢?有什麼法寶?#
它之所以快,有兩個原因。首先 Go 有兩個編譯器 —— 兩個單獨的實現。一個是按照 Plan 9(http://plan9.bell-labs.com/wiki/plan9/1/)風格新寫的編譯器,它有自己獨特的工作方式,是個全新的編譯器。另一個編譯器叫做 GCC Go,它擁有 GCC 前端,這個編譯器是 Ian Taylor 後來寫的。所以 Go 有兩個編譯器,速度快是二者的共同特點,但是 Plan 9 風格編譯器的速度是 GCC Go 的 5 倍,因為它從頭到腳都是全新的,沒有 GCC 後端,那些東西會花很多時間來產生真正的好代碼。
GCC Go 編譯器要產生更好的代碼,所以速度慢些。不過真正重要的一點是 Go 編譯器的依賴管理特性才是其編譯速度快的真正原因。如果你去看一個 C 或 C++ 程序,便會發現其頭文件描述了函數庫、對象代碼等等東西。語言本身並不強制檢查依賴,每一次你都必須分析代碼以便清楚你的函數是怎樣的。如果你編譯過程中想用另一個類的 C++ 程序,你必須先編譯它所依賴的類和頭文件等等等等。如果你所編譯的 C++ 程序有許多類,並且內部相關,你可能會把同一個頭文件編譯數百次甚至上千次。當然,你可以用預編譯頭文件及其他技巧來回避之一問題。
但是語言本身並不能幫上你的忙,工具可能會讓這一問題得到改善,可是最大的问题是並沒有什麼能保證你所編譯的東西就是程序真正需要的東西。有可能你的程序包含了一個並不真正需要的頭文件,但是你沒辦法知道,因為語言並沒有強制檢查。而 Go 有一個更加嚴格的依賴模型,它有一些叫做包(packages)的東西,你可以把它想象成 Java 類文件或著類似的東西,或者函數庫什麼的,雖然他們並不相同,但基本思路是相同的。關鍵問題是,如果這個東西依賴那個東西,而那個東西又依賴另外一個東西,比如 A 依賴於 B,B 又依賴於 C,那麼你必須首先編譯最內層的依賴:即,你先編譯 C,然後編譯 B,最後編譯 A。
但是如果 A 依賴 B,但是 A 並不直接依賴於 C,而是存在依賴傳遞,那麼該怎麼辦呢?這時所有 B 需要從 C 拿到的信息都會被放在 B 的對象代碼裡。這樣,當我編譯 A 的時候,我不需要再管 C 了。於是事情就非常簡單了:在你編譯程序時,你只需將類型信息沿著依賴關係樹向上遍歷即可,如果你到達樹的頂端,則只需編譯緊鄰的依賴,而不用管其它層級的依賴了。如果你要做算術運算,你會發現在 Objective-C 或 C++ 或類似的語言裡,雖然只包含了一個簡單的頭文件,但由於依賴傳遞的存在,你可能會編譯數十萬行程序。然而在 Go 中,你打開一個文件,裡面或許只有 20 行,因為其中只描述了公共接口。
如果一個依賴鏈裡只有三個文件,Go 的優勢可能並不明顯,但是如果你有成千上萬個文件的時候,Go 的速度優勢會成指數增長。我們相信,如果用 Go 的話,我們應該能夠在數秒內就編譯完數百萬行代碼。然而如果是等量的用 C++ 編寫的程序,由於依賴管理問題,編譯的開銷會大得多,編譯的時間將會長達若干分鐘。因此,Go 速度快的根源主要歸功於對依賴的管理。
4. 讓我們開始聊聊 Go 裡的類型系統吧。Go 裡有結構(struct)、有類型(type),那麼 Go 裡的類型是什麼?#
Go 裡的類型與其它傳統編程語言裡的類型是類似的。Go 裡的類型有整數、字符串、struct 數據結構、以及數組(array),我們稱之為切片(slice),它們類似於 C 的數組,但更易於使用,更加固定一些。你可以聲明本地類型並予以命名,然後按照通常的方式來使用。Go 和面向對象方式的不同之處在於,類型只是書寫數據的一種方式,方法則是一個完全獨立的概念。你可以把方法放在 struct 上,在 Go 裡沒有類的概念,取而代之的是結構,以及為此結構聲明的一些方法。
結構不能與類混為一談。但是你也可以把方法放在數組、整數、浮點數或字符串上,實際上任何類型都可以有方法。因此,這裡方法的概念比 Java 的方法更加泛化,在 Java 裡方法是類的一部分,僅此而已。例如,你的整數上可以有方法,聽上去似乎沒什麼用,但是如果你想在一個叫做 Tuesday 的整數常量上附加上 to_string 方法來打印出漂亮的星期格式;或者,你想重新格式化字符串使其能夠以不同的方式打印出自己,這時你就會意識到它的作用。為什麼非要把所有方法或者其它好東西都塞進類裡面呢,為什麼不讓它們提供更廣泛的服務呢?
5. 那麼這些方法只是在包內部可見喽?#
非也,實際上是這樣,Go 只允許你在包內為你所實現的類型定義方法。我不能引入你的類型然後直接把我的方法增加進去,但是我可以使用匿名屬性(anonymous field)將其包裹起來,方法可不是你想加到哪就加到哪的,你要定義類型,然後才能把方法放在上面。正因如此,我們在包裡提供了另一種封裝 —— 接口(interface),但是如果你不明白誰能為對象增加方法的嚴格界限,就很難理解接口。
6. 你的意思是,我可以給 int 增加方法,但是必須先使用 typedef 嗎?#
你要 typedef 一個整數類型,起個名字,如果你正在處理一星期中的七天,可以就叫它 “Day”,你可以給你所聲明的類型 ——Day 增加方法,但是你不能直接給 int 增加方法。因為整數類型不是你定義的,不在你的包裡,它是引入的但並不在你的包中定義,這就意味著你不能給其增加方法。你不能給不在你包裡定義的類型增加方法。
7. 你們借鑒了 Ruby 裡開放類的思想,這很有意思。Ruby 的開放類實際上是可以修改類並增加新的方法,這是有破壞性的,但是你們的方法本質上是安全的,因為創建了新的東西。#
它是安全可控的,而且很容易理解。最初我們覺得類型用起來可能不太方便,我們也希望像 Ruby 那樣添加方法,但這又讓接口比較難以理解。所以,我們只把方法取出來,而不是放進去,我們想不出有什麼更好的辦法,於是限制方法只能在本地類型上,不過這種思路確實很容易理解和使用。
8. 你還提到了 typedef,是叫 typedef 吧?#
應該叫 “type”,你所說的類型 ——Day 的定義方式是這樣 “type Day int”,這樣你就有一個新類型了,你可以在其上增加方法、聲明變量,但這個類型不同於 int,不像 C 那樣,只是同一事物另起了個名字而已,在 Go 裡實際上你創建了一個不同於 int 的新類型,叫做 “Day”,它擁有 int 的結構特性,但卻有自己的方法集。
9. Typedef 在 C 裡是一種預處理指令嗎?【編輯注 / 免責聲明:C 語言裡的 typedef 與預處理無關】#
那實際上就是個別名,但在 Go 裡不是別名,是新類型。
10. 我們從底層說起吧,在 Go 裡最小的類型是什麼?#
最小的類型應該是布爾類型(bool)吧。bool、int 和 float,然後是 int32、float64 之類有尺寸的類型、字符串、複雜類型,可能有遺漏,但這就是基本類型集了。你可以由這些類型構建結構、數組、映射(map),映射在 Go 裡是內建類型不是函數庫。然後我想就該是接口了,到了接口,有趣的東西才真正開始。
11. 但是,int 這樣的類型是值類型對吧.#
Int 是值類型。在 Go 裡,任何類型都是值類型,和 C 一樣,所有東西都是按值調用,但是你也可以用指針。如果你想引用某樣東西,可以獲取其地址,這樣你就有了一個指針。Go 也有指針但是比 C 指針有更多限制,Go 裡的指針是安全的,因為他們是類型安全的,所以你沒法欺騙編譯器,而且也沒有指針運算,因此,如果你有個指向某物的指針,你無法將其移到對象外,也無法欺騙編譯器。
12. 它們類似 C++ 的引用嗎?#
是的,很像引用,但是你可以按照你預期的方式對它們進行寫操作。而且你可以使用結構內部(如緩衝區)中間的某個地址,它和 Java 的引用不一樣。在 Java 中,你必須在旁邊分配一個緩衝區,這是額外的開銷。在 Go 中,你實際上把該對象分配為結構的一部分,在同一內存塊中,這對性能是非常重要的。
13. 它是結構內部一個複合對象。#
是的,如果它是值而不是指針的話,是這樣。當然你也可以把指針放在結構內部和外部,但是如果你有 struct A,而把 struct B 放在 struct A 裡,那麼 stuct B 就是一塊內存,而不像 Java 那樣,這也是 Java 性能問題的原因之一。
14. 你提到過接口比較有趣,那下面咱們就談談這一部分。#
Go 裡的接口真的非常、非常地簡單。接口指明了兩個不同事情:其一,它表明了類型的構思,接口類型是一個羅列了一組方法的類型,因此如果你要抽象一組方法來定義一個行為,那麼就定義一個接口並聲明這些方法。現在你就有了一個類型,我們就叫它接口類型吧,那麼從現在起所有實現了接口中這些方法的類型 —— 包括基本類型、結構、映射(map)或其它什麼類型,都隱含符合該接口要求。其二,也是真正有意思的是,和大多數語言中的接口不同的是,Go 裡沒有 “implements” 聲明。
你無須說明 “我的對象實現了這個接口”,只要你定義了接口中的那些方法,它就自動實現了該接口。有些人對此感到非常擔憂,依我看他們想說的是:知道自己實現(Implement)了什麼接口真的很重要。如果你真想確定自己實現了什麼接口,還是有技巧可以做到這一點的。但是我們的想法與此截然不同,我們的想法是你不應該考慮實現什麼接口,而是應該寫下要做的東西,因為你不必事前就決定要實現哪個接口。可能後來你實際上實現了某個現在你尚不知曉的接口,因為該接口還未設計出來,但是現在你已經在實現它。
後來你可能發現兩個原先未曾考慮過相關性的類具有了相關性 —— 我又用了類這個詞,我思考 Java 太多了 —— 兩個 structs 都實現了一些非常有用的小子集中的相關方法,這時有辦法能夠操作這兩個 structs 中的任意一個就顯得非常有用了。這樣你就可以聲明一個接口,然後什麼都不用管了,即使這些方法是在別人的代碼中實現的也沒問題,雖然你不能編輯這些代碼。如果是 Java,這些代碼必須要聲明實現你的接口,在某種意義上,實現是單向的。然而在 Go 裡,實現是雙向的。對於接口實際上有不少漂亮而簡單的例子。
我最愛用的一個真實例子就是 “Reader”,Go 裡有個包叫做 IO,IO 包裡有個 Reader 接口,它只有一個方法,該方法是 read 方法的標準聲明,比如從操作系統或文件中讀取內容。這個接口可以被系統中任何做 read 系統調用的東西所實現。顯然,文件、網絡、緩存、解壓器、解密機、管道,甚至任何想訪問數據的東西,都可以給其數據提供一個 Reader 接口,然後想從這些資源中讀取數據的任何程序都可以通過該接口達到目的。這有點像我們前面說過的 Plan 9,但是用不同的方式泛化的。
與之類似,Writer 也是比較好理解的另一個例子,Writer 由那些要做寫操作的人來實現。那麼在做格式化打印時,fpringf 的第一參數不是 file 了,而是 Writer。這樣,fprintf 可以給任何實現了 write 方法的東西做 IO 格式化的工作。有很多很好的例子:比如 HTTP,如果你正在實現一個 HTTP 服務器,你僅須對 connection 做 fprintf,便可將數據傳遞到客戶端,不需要任何花哨的操作。你可以通過壓縮器來進行寫操作,你可以通過我所提到的任何東西來進行寫操作:壓縮器、加密機、緩存、網絡連接、管道、文件,你都可以通過 fprintf 直接操作,因為它們都實現了 write 方法,因此,隱含都隱含符合 writer 接口要求。
15. 某種程度上有點類似結構化類型系統(structural typing)#
不考慮它的行為的話,它是有點像結構化類型系統。不過它是完全抽象的,其意並不在擁有什麼,而是能做什麼。有了結構(struct)之後,就規定了其內存的樣子,然後方法說明了結構的行為,再之後,接口則抽象了該結構及其它實現了相同方法的其他結構中的這些方法。這是一種鴨子類型系統(duck typing,一種動態類型系統,http://en.wikipedia.org/wiki/Duck_typing),而不是結構化類型系統。
16. 你提到過類,但 Go 沒有類,對吧。#
Go 沒有類。
17. 但是沒有類怎麼去寫代碼?#
帶方法的結構(stuct)很像是類。比較有意思的不同之處是,Go 沒有子類型繼承,你必須學習 Go 的另類寫法,Go 有更強大、更有表現力的東西。不過 Java 程序員和 C++ 程序員剛開始使用 Go 的時候會感到意外,因為他們實際上在用 Go 去編寫 Java 程序或 C++ 程序,這樣的代碼工作得並不好,你可以這樣做,但這樣就略顯笨拙了。但是如果你退一步,對自己說 “我該怎樣用 Go 去編寫這些東西呢?”,你會發現模式其實是不同的,用 Go 你可以用更短的程序來表達類似的想法,因為你不需要在所有子類裡重複實現行為。這是個非常不同的環境,比你第一眼看上去的還要不同。
18. 如果我有一些行為要實現,而且想放在多個 structs 裡,怎麼去共享這些行為?#
有一個叫做匿名域的概念,也就是所謂的嵌入。其工作方式是這樣:如果你有一個結構(struct),而又有一些其它東西實現了你想要的行為,你可以把這些東西嵌入到你的結構(struct)裡,這樣,這個結構(struct)不僅僅可以獲得被嵌入者的數據還可以獲得它的方法。如果你有一些公共行為,比如某些類型裡都有一個 name 方法,在 Java 裡的話你會認為這是一組子類(繼承來的方法),在 Go 裡,你只需拿到一個擁有 name 方法的類型,放在所有你要實現這個方法的結構裡,它們就會自動獲得 name 方法,而不用在每個結構裡都去寫這個方法。這是個很簡單的例子,但有不少有趣的結構化的東西使用到了嵌入。
而且,你還可以把多個東西嵌入到一個單一結構中,你可以把它想象成多重繼承,不過這會讓人更加迷惑,實際在 Go 裡它是很簡單的,它只是個集合,你可以放任何東西在裡面,基本上聯合了所有的方法,對每個方法集合,你只需寫一行代碼就可以擁有其所有行為。
19. 如果有多重繼承命名衝突的問題該怎麼辦?#
命名衝突實際上並沒什麼,Go 是靜態處理這一問題的。其規則是,如果有多層嵌入,則最高層優先;如果同一層有兩個相同的名字或相同的方法,Go 會給出一個簡單的靜態錯誤。你不用自己檢查,只需留意這個錯誤即可。命名衝突是靜態檢查的,而且規則非常簡單,在實踐中命名衝突發生的也並不多。
20. 因為系統中沒有根對象或根類,如果我想得到一個擁有不同類型的結構的列表,應該怎麼辦?#
接口一個有意思的地方是他們只是集合,方法的集合,那麼就會有空集合,沒有任何方法的接口,我們稱之為空接口。系統中任何東西都符合空接口的要求。空接口有點類似於 Java 的 Object,不同之處在於,int、float 和 string 也符合空接口,Go 並不需要一個實際的類,因為 Go 裡沒有類的概念,所有東西都是統一的,這有點像 void*,只不過 void * 是針對指針而不是值。
但是一個空接口值可以代表系統中的任何東西,非常具有普遍性。所以,如果創建一個空接口數組,實際上你就有了一個多態性容器,如果你想再把它拿出來,Go 裡有類型開關,你可以在解包的時候詢問裡面的類型,因此可以安全的進行解包操作。
21. Go 裡有叫做 Goroutines 的東西,它們和 coroutines 有什麼區別?不一樣麼?#
Coroutines 和 Goroutines 是不同的,它們的名字反映了這一點。我們給它起了個新名,因為有太多術語了,進程(processes)、線程(threads)、輕量級線程、弦(chords),這些東西有數不清的名字,而 Goroutines 也並不新鮮,同樣的概念在其它系統裡已經都有了。但是這個概念和前面那些名字有很大不同,我希望我們自己起名字來命名它們。Goroutine 背後的含義是:它是一個 coroutine,但是它在阻塞之後會轉移到其它 coroutine,同一線程上的其它 coroutines 也會轉移,因此它們不會阻塞。
因此,從根本上講 Goroutines 是 coroutines 的一個分支,可在足夠多的操作線程上獲得多路特性,不會有 Goroutines 會被其他 coroutine 阻塞。如果它們只是協作的話,只需一個線程即可。但是如果有很多 IO 操作的話,就會有許多操作系統動作,也就會有許多許多線程。但是 Goroutines 還是非常廉價的,它們可以有數十萬之眾,總體運行良好並只占用合理數量的內存,它們創建起來很廉價並有垃圾回收功能,一切都非常簡單。
22. 你提到你們使用了 m線程模型,即 m 個 coroutines 映射到 n 個線程上?#
對的,但是 coroutines 的數量和線程的數量是按照程序所做工作的動態決定的。
23. Goroutines 有用於通信的通道嗎?#
是的,一旦有兩個獨立執行的功能,如果 Goroutine 們要相互協作它們就需要相互對話。所以就有了通道這個概念,它實際上是一個類型消息隊列,你可以用它來發送值,如果你在 Goroutine 中持有通道的一端,那麼你可以發送類型值給另外一端,那一端則會得到想要的東西。通道有同步和異步之分,我們儘可能使用同步通道,因為同步通道的構思非常好,你可以同時進行同步和通信,所有東西運行起來都步調一致。
但是有時由於效率原因或調度原因,對消息進行緩存也是有意義的。你可以向通道發送整型消息、字符串、結構、指向結構的指針等任何東西,非常有意思的事,你可以在通道上發送另一個通道。這樣,我就能夠把與他人的通信發送給你,這是非常有意思的概念。
24. 你提到你們有緩存的同步通道和異步通道。#
不對,同步是沒有緩存的;異步和緩存是一個意思,因為有了緩存,我才能把值放在緩存的空間裡進行保存。但是如果沒有緩存,我必須等著別人把值拿走,因此無緩存和同步是一個意思。
25. 每個 Goroutine 就像是一個小的線程,可以這麼給讀者解釋吧。#
對,但是輕量級的。
26. 它們是輕量級的。但是每個線程同樣都預分配棧空間,因而它們非常耗費資,Goroutines 是怎麼處理的呢?#
沒錯,Goroutines 在被創建的時候,只有非常小的一個棧 ——4K,可能有點小吧,這個棧是在堆中的,當然,你知道如果在 C 語言裡有這麼一個小棧會發生什麼,當你調用函數或分配數組之類的東西時,程序會馬上溢出。在 Go 裡則不會發生這樣的事情,每個函數的開頭都會有若干指令以檢查棧指針是否達到其界限,如果到達界限,它會鏈接到其它塊上,這種鏈接的棧叫做分段棧,如果你使用了比剛開始啟動時更多的棧,你就有了這種棧塊鏈接串,我們稱之為分段棧。
由於只有若干指令,這種機制非常廉價。當然,你可以分配多個棧塊,但是 Go 編譯器更傾向於將大的東西移到堆上,因此實際上典型的用法是,你必須在達到 4K 邊界之前調用幾個方法,雖然這並不經常發生。但是有一點很重要:它們創建起來很廉價,因為僅有一次內存分配,而且分配的內存非常小,在創建一個新的 Goroutine 時你不用指明棧的尺寸,這是很好的一種抽象,你根本不用擔心棧的大小問題。之後,棧會隨需求增長或縮小,你不用擔心遞歸會有問題,你也不用擔心大的緩存或任何對程序員完全不可見的東西,一切由 Go 語言來打理,這是一門語言的整體構思。
27. 我們再來談談自動化方面的東西,最初你們是將 Go 語言作為系統級語言來推廣的,一個有趣的選擇是使用了垃圾回收器,但是它速度並不快或者說有垃圾回收間歇問題,如果用它寫一個操作系統的話,這是非常煩人的。你們是怎麼看這一問題的?#
我認為這是個非常難的問題,我們也還沒有解決它,我們的垃圾回收器可以工作,但是有一些延遲問題,垃圾回收器可能會停頓,但是我們的看法是,我們相信儘管這是一個研究課題,雖還沒解決但是我們正在努力。對於現今的並行機,通過把機器內核的一些碎片專門分給作為後台任務的垃圾回收來進行並行回收是可行的。在這一領域有很多工作要做,也取得了不少成功,但這是個很微妙的問題,我不認為而我們會把延遲降為 0,但是我相信我們可以讓延遲盡可能低,這樣對於絕大多數系統軟件來講它不再是個問題。我不保證每個程序都不會有顯著延遲,但是我想我們可以獲得成功,而且這是 Go 語言中一個比較活躍的領域。
28. 有沒有方法能夠避免直面垃圾回收器,比如用一些大容量緩存,我們可以把數據扔進去。#
Go 可以讓你深入到內存佈局,你可以分配自己的空間,如果你想的話可以自己做內存管理。雖然沒有 alloc 和 free 方法,但是你可以聲明一個緩存把東西放進去,這個技巧可用來避免產生不必要的垃圾。就像在 C 語言一樣,在 C 裡,如果你老是 malloc 和 free,代價很大。因此,你分配一個對象數組並把它們鏈接在一起,形成一個鏈表,管理你自己的空間,而且還不用 malloc 和 free,那麼速度會很快。你可以做與 Go 所做相同的事情,因為 Go 賦予你與底層事物安全打交道的能力,因此不用欺騙類型系統來達到目的,你實際上可以自己來做。
前面我表達了這樣的觀點,在 Java 裡,無論何時你在結構裡嵌入其它東西,都是通過指針來實現的,但在 Go 裡你可以把它放在一個單一結構中。因此如果你有一些需要若干緩存的數據結構,你可以把緩存放在結構的內存裡,這不僅意味著高效(因為你不用間接得到緩存),而且還意味著單一結構可以在一步之內進行內存分配與垃圾回收。這樣開銷就會減少。因此,如果你考慮一下垃圾回收的實際情況,當你正在設計性能要求不高的東西時,你不應該總是考慮這個問題。但如果是高性能要求的,考慮到內存佈局,儘管 Go 是具有真正垃圾回收特性的語言,它還是給了你工具,讓你自己來控制有多少內存和產生了的垃圾。我想這是很多人容易忽略的。
29. 最後一個問題:Go 是系統級語言還是應用級語言?#
我們是把他設計為一種系統級語言,因為我們在 Google 所做的工作是系統級的,對吧?Web 服務器和數據庫系統、以及存儲系統等,這些都是系統。但不是操作系統,我不知道 Go 是否能成為一個好的操作系統語言,但是也不能說它不會成為這樣的語言。有趣的是由於我們設計語言時所採用的方法,Go 最終成為了一個非常好的通用語言,這有點出乎我們意料。我想大多數用戶並沒有實際從系統觀點來考慮過它,儘管很多人做過一點 Web 服務器或類似東西。
Go 用來做很多應用類的東西也非常不錯,它將會有更好的函數庫,越來越多的工具以及一些 Go 更有用的東西,Go 是一個非常好的通用語言,它是我用過的最高產的語言。