全世界有上千種程序開發語言,其實自己要發明一種語言也不是很難的事情。但問題是,為什么需要新語言,尤其是通用軟件開發語言?
一般來說,語言是一種工具,當工具不夠用的時候自然會有更新工具甚至換一種工具的需求。按照 TIOBE 開發語言排名來看,前20種語言已經占據了超過 75% 的開發量,這些語言在絕大部分場合都是夠用了。
然而,作為技術界走在前面的 Google 可不是這么想的。鑒于現有的語言們都有這樣那樣的問題,因此它在2007年推出了一種新的通用語言:Go。
自從1967年 Simula 語言第一次引入了面向對象程序設計的雛形以來,OOP(Object-Oriented Programming)就占據了軟件開發思想的主導地位。當然這需要歸功于 C++ 及其的衍生語言們 Java、C# 等。以至于現在說起 OOP,可能大家第一印象就是 C++、Java 中的 class。
但 Google 覺得完全不是這么回事,從 C++ 開始就走錯了路,語法越來越復雜、學習門檻越來越高、維護越來越困難,反觀 C 語言本身,雖然在語言層面不支持 OOP,但經久不衰,在 TIOBE 開發語言排名上,C 的使用量幾乎是 C++ 的2 倍還多,究其原因,在于 C 已經足夠強大且足夠簡單。
傳統的桌面軟件開發如今被移動開發、互聯網開發追趕,大規模和高性能的軟件開發的需求越來越明確,C++ 和它的繼任者們總有這樣那樣的力所不逮。因此新的語言,比如 Go,就應運而生。
1、你有什么特別的,Go?
在深入 Go 之前,先讓我們看一下兩段功能上基本一致的代碼。
C++ 的版本:
Go 的版本:
有什么不一樣?好像沒什么不一樣吧?等一等,為什么 Go 沒有 class?是的,Go 并沒有 class,實際上,不僅沒有 class,所有和 class 相關的,比如構造函數、虛擬函數都是沒有的。
OOP 對我只代表消息、局部持有和保護、狀態處理的隱藏,以及對所有事物盡可能的延后綁定。
——Alan Kay
注:Alan Kay:Alan Curtis Kay,是美國計算機科學家,在面向對象編程和窗口式圖形用戶界面方面做出了先驅性貢獻,他是 Smalltalk 的最初設計者。2003年獲得圖靈獎。
Go 忠實地實踐了 Alan 的理想,而沒有使用 C++ 們所引入的概念,包括繼承和多態等。原始的概念讓我們可以從另外一個角度來審視復雜系統的設計,同時來欣賞這些概念所帶來的簡潔性。
從 OOP 的角度上來說,類并不是必須的概念,這只是一種被刻意特化的類型,賦予了承載 OOP 的重任,但對于其它的一些語言來說,典型的比如 C 語言,即使沒有這些機制,一樣可以實現 OOP。
2、沒有class,沒有 this
在 Go 的這個例子里,類型 Connection 就是一個結構,和其它在 C 和 C++中被稱為結構的東西是一樣的。而 Connect() 這樣的方法表示向 Connection 對象發送的一個消息。
請再等一下,發送消息?這個說法有些耳熟——實際上,另外一個語言采用了相同的概念,那就是近年來日漸流行的 Objective-C。不同的是,Objective-C 采用的是運行時動態消息傳遞,而 Go 采用了靜態消息傳遞。并且,Go 做得更加徹底,在 Go 中方法可以向任意類型(除了指針以外)發送消息,接收消息的對象在 C++ 中稱為 this 指針,在 Objective-C 中稱為self,而在 Go 中則可以用任意的變量表示——在這個例子中,就是 conn——并且需要顯式聲明,且也不一定需要是指針。
為什么不使用 this?問題應該是,為什么是使用 this?本質上 Go 不認為這個方法屬于這個對象,this 也好,self 也好,都在強化這個概念,因此在 Go 中不建議這樣使用。
3、只有組合,沒有繼承
在 HttpConnection 這個結構里看到了那個奇怪的 Connection 聲明了嗎?嚴格說起來這是一個匿名結構成員,在 HttpConnection 這個對象中組合了一個 ?Connection 對象。你可以組合任意多的對象,但在這個例子中,但它承擔起了和其它語言中基類的作用。
C++ 中類內存布局規定,基類必須處于派生類內存布局的前部,但在 Go 中,開發者可以自己定義什么地方出現這個基類的實例。并且由于需要顯式引用這個對象的實例,因此當組合了多個對象時,就和多重繼承非常相似了。
繼承有什么不好?在代碼依賴關系中,繼承是一種非常強的依賴關系,一旦代碼寫成,在不修改源代碼的情況下幾乎不可能改變。對于設計來說,只有一次機會來判斷這樣的設計是否正確,一旦設計不準確,那么再無修改的可能。然而做出這樣的判斷,是一件很困難的事情。
在傳統的 OOP 教材中往往會有一個例子類似于這樣:
貓是一種動物,貓會喵喵叫,黑貓是一種貓,它是黑色的,但它也會喵喵叫。所以貓應當從動物繼承,而黑貓應當從貓繼承。
正確嗎?未必。
如果有一種黑貓是嗚嗚叫的話,就會繼承自黑貓,并改寫“叫”這個方法。然而,如果是有一種白貓也是嗚嗚叫的呢?或者一種短尾的貓也是嗚嗚叫的呢?雖然多態性能夠改變一些行為,但就從重用的角度上看,這不是合理的設計。
如果把“叫”作為一個可以組合的功能,那么在任何一種貓重用嗚嗚叫和喵喵叫,那么都是在運行時的一個賦值而已。
4、特殊的接口
接口是什么?其它語言中接口主要作為不同組件之間的契約存在,并且是強制的。接口作為一種類型,需要顯式地聲明某個類實現了這個接口。
還是以貓的例子:貓會叫,因此叫這個動作作為一個接口被貓這個對象實現了,然而貓也會爬,所以它還需要實現一個爬的接口。然而這種做法一點也不自然,并不是因為實現了爬這個接口,貓才是貓,難道不應該是先有了貓,才歸納出有爬這個動作嗎?傳統的接口概念就是這樣一個本末倒置的狀態,一旦對象的特性太復雜了,為了合理分解接口,這個任務會變得異常困難。
既然是契約,那么 Go 另辟蹊徑,在 Go 中,接口只是方法的集合,一個對象實現了一個接口的所有方法,就說,這個對象實現了這個接口,而不需要繼承、關聯這個接口類型,實際上,對象在實現的時候甚至都不需要知道這個接口是否存在。
如果存在下面的接口:
type IConnectable interafce {
Connect(address string)
}
因為 HttpConnection 和 Connection 對象都實現了 Connect(address string)這個方法,因此這兩個對象已經實現了 IConnectable 這個接口,甚至我們在實現那兩個對象時,還沒有定義這個接口!
下面這樣的賦值就是合法的:
var conn IConnectable = new(HttpConnection)
5、其它特性
從 OOP 的角度上說,Go 采用了更為傳統和淳樸的概念,相比于現在流行的 ?C++風格的 OOP 概念,Go 的概念更加簡潔,更加靈活。
除了 OOP 的概念之外,作為一個現代語言,Go 突出的另外一個特性是它并發機制:goroutine 和 chan。相比于其它主流語言,它的并發機制異常簡單和高效,相當于 C++ 數千行代碼的并發機制在 Go 中只需要幾句話即可實現,線程間通訊、緩存、超時,各類機制一應俱全,這可以在另外的文章中介紹。
“To be or not to be ,that's a question."
——William Shakespeare
“To GO or not to GO, that's a question.”
注:
http://www.tiobe.com/tiobe-index//,一個著名的開發語言排名的統計網站
2016年8月,Go 正式邁入前20名的開發語言隊伍
本文作者:徐翎 Andrew(點融黑幫),任職點融網客戶端開發總監,組建了移動和網站的開發團隊,開發了點融網各款客戶端軟件。曾就職于微軟等公司,參與過包括Hotmail 和Windows 在內的大型跨國際軟件開發項目的研發。