這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。
這篇文章是我看了《Rob Pike談Google Go:並發,Type System,記憶體管理和GC》這後的一個總結,原始的訪談文章請點擊這裡:Rob Pike談Google Go:並發,Type System,記憶體管理和GC。
雖然我個人不是很喜歡Go的文法,但是看了這個訪談,我還是被Go的一些特性所吸引。世界上沒有包治百病的靈丹妙藥,不存在所謂的“銀彈”,當我在使用Java的時候,Go的這些特性正是我苦苦找尋的東西:
Go擁有非常快的編譯器和編譯速度
Go目前為止有兩個編譯器,一個是按照Plan 9風格編寫的,另一個是Gcc Go,儘管兩個編譯器相較其他語言的編譯器已經非常快了,但是其中Plan 9風格的速度比Gcc Go還要快上5倍。
Rob Pike解釋了Go編譯器快的主要原因。傳統語言比如C或者C++,它們本身並不強制檢查依賴,所以每一次編譯都必須分析代碼以便清楚程式依賴的函數是怎樣的,這樣就會重複編譯某些被不同模組依賴的相同的類或者標頭檔;而Go有一個嚴格的依賴模型,它有一些叫做包(packages)的東西,很像Java類檔案或著類似的東西,或者函數庫什麼的,雖然他們並不相同,但基本思路是一樣的。當A依賴B,B又依賴C時,那麼首先會編譯C,然後是B和A;但是如果A依賴B,但是A並不直接依賴於C,而是存在依賴傳遞,這時會把所有B需要從C拿到的資訊放在B的對象代碼裡。這樣,當編譯A的時候,就不需要再管C了。於是事情就非常簡單了:在編譯器時,只需將類型資訊沿著相依樹狀結構向上遍曆即可,如果到達樹的頂端,則只需編譯緊鄰的依賴,而不用管其它層級的依賴了。
Rob Pike說像Go現在的編譯器在大型系統中進行編譯,速度與C++相比是秒層級和分鐘層級的對比關係。可見Go編譯速度只快。
Go的類型系統
Go的類型有整數、字串、struct資料結構、以及數組(array),Go裡稱之切片(slice)。Go裡沒有類,只有struct。Go裡的方法比Java中的方法更加寬泛,它可以加到任何自己定義的類型上,但是不像Ruby,它不能破壞已經定義好的類型,因此Go在這方面更加安全。Go可以使用type關鍵字來定義一個基於現有類型的類型,它不同於C中的別名,比如type Day int,這裡定義的Day擁有int的結構特性,但是可以讓我們加入自己的方法集。
實值型別和指標
在Go裡,任何類型都是實值型別,所有東西都是按值調用的。Go中也可以使用指標,但是和C++的指標不同,Go中的指標有更多的限制,並且是型別安全的,沒有指標運算,我們無法將指標移到對象之外,也不能欺騙編譯器。
不用implements的結構
Go裡有介面,同樣也是一組方法的集合。但是Go裡面的類型不用去聲明implements(實現)某個介面,當某個類型定義了某個介面中的所有方法時,這個類型就implements(實現)了這個介面。Rob Pike解釋說,這麼設計可以讓開發人員更關注於要做什麼東西,而不是去實現什麼介面。他舉了一個例子:比如有兩個struct都實現了一些非常有用的小子集中的相關方法,這時有辦法能夠操作這兩個structs中的任意一個就顯得非常有用了。這樣我們就可以聲明一個介面,然後什麼都不用管了,即使這些方法是在別人的代碼中實現的也沒問題,雖然我們不能編輯這些代碼。如果是Java,這些代碼必須要聲明實現這個的介面,在某種意義上,實現是單向的。然而在Go裡,實現是雙向的。這是一種鴨子類型系統。
沒有類,怎麼實作類別似於繼承的功能
Go的struct類型可以嵌套其他已經存在的類型,嵌套之後可以獲得被嵌入者的資料和它的方法。關於可能會出現的命名衝突,Go是靜態處理這一問題的。其規則是,如果有多層嵌入,則最高層優先;如果同一層有兩個相同的名字或相同的方法,Go會給出一個簡單的靜態錯誤。我們不用自己檢查,只需留意這個錯誤即可。命名衝突是靜態檢查的,而且規則非常簡單,在實踐中命名衝突發生的也並不多。
Go中的Goroutine
Goroutine在Go中可以看作是一個非常輕量級的小線程。Goroutine在建立的時候,會在堆上為其分配大小4K的棧,隨後這個棧會根據實際使用自動增大或者縮小,我們不用擔心會溢出。
Goroutine之間可以通過同步通道和非同步通道進行通訊,通訊的訊息是任意的,甚至可以把通道當作訊息發送出去。同步通道是沒有緩衝的,只有非同步通道才需要緩衝。
Go的GC效率
Go是系統級的語言,但是它提供了GC功能,關於GC的效率,Rob Pike表示說他們正在不斷的進行研究,因為在這個領域還有許多的工作需要做,他們不認為將來會將GC的延遲降為0,但是他們會儘可能的去提高GC的效率。