Go語言:基於串連與組合的語言(上)

來源:互聯網
上載者:User

到目前為止,我做過不下於10次關於Go的講座,大多數的主題都會與“設計哲學”這樣的話題有關。之所 以這樣,是因為我對自己的定位是Go語言的“傳教士”,而不是“培訓師”。我的出發點在於引起大家對Go的 關注與興趣,至於如何去一步步學習Go語言的文法知識,我相信興趣是最好的老師。現今我們學習的平台足夠 強大,只要你真的很有興趣,就一定能夠學好Go語言。

Go語言是非常簡約的語言。簡約的意思是少而 精。Go語言極力追求語言特性的最小化,如果某個文法特性只是少些幾行代碼,但對解決實際問題的難度不會 產生本質的影響,那麼這樣的文法特性就不會被加入。Go語言更關心的是如何解決程式員開發上的心智負擔。 如何減少代碼出錯的機會,如何更容易寫出高品質的代碼,是Go設計時極度關心的問題。

Go語言也是 非常追求自然(nature)的語言。Go不只是提供極少的語言特性,並極力追求語言特性最自然的表達,也就是 這些文法特性被設計成恰如多少人期望的那樣,盡量避免驚異。事實上Go語言的文法特性上的爭議是非常之少 的。這些也讓Go語言的入門門檻變得非常低。

今天我的話題重心是關於Go語言編程範式的流派問題。 這仍然是關於“設計哲學”方面的。到目前為止,大家可能聽過的編程範式主要如下:

過程式(代表:C)

物件導向(代表:Java、C#)

面向訊息(代表:Erlang)

函數式(代表:Haskell、Erlang)

過程式編程的代表概念是過程(函數)。這是一個非常古老的流派,基本上所有語言都有過程式的影子。 但是比較純粹的過程式的主流語言比較少,通常比較古老,C是其中最典型的代表。

物件導向編程是目 前廣為接受、影響極其深遠的流派。物件導向有很多概念:如類、方法、屬性、重載、多態(虛函數)、構造 和析構、繼承等等。Java、C#是其中最典型的代表。Go語言支援物件導向,但將特性最小化。Go語言中有結構 體(類似物件導向中的類),結構體可以有方法,這就是Go對物件導向支援的所有內容。Go語言的物件導向特 征少得可憐。結構體是構成綜合物件的基礎,只要有組合,通常就由結構體,像C這樣的過程式語言,照樣有 結構體。所以Go身上沒有多少物件導向的烙印,Go 甚至反對繼承,拒絕提供繼承文法。

面向訊息編程 是個比較小眾的編程流派,因為分布式與並發編程的強烈訴求而崛起。面向訊息編程的主體思想是推薦基於消 息而不是基於鎖和共用記憶體進行並發編程。Erlang語言是面向訊息編程的代表。Go語言中有面向訊息的影子。 因為Go語言中有channel,可以讓執行體(goroutine)之間相互發送訊息。但channel只是Go語言的基礎文法 特性,Go並沒有杜絕鎖和共用記憶體,所以它並不能算面向訊息編程流派。

函數式編程也是一個小眾的 流派,儘管曆史非常悠久。函數式編程中有些概念如:閉包、柯裡化、變數不可變等。Haskell、Erlang都是 這個流派的代表。函數式編程之所以小眾,個人認為最重要的原因,是理論基礎不廣為人知。我們缺乏面向函 數式編程的資料結構學。因為變數不可變,資料結構學需要用完全不同思維方式來表達。比如在傳統命令式的 編程方式中,數組是最簡單的基礎資料結構,但函數式編程中,數組這樣的資料結構很難提供(修改數組的一 個元素成本太高,Erlang語言中數組這個資料結構很晚才引入,用tree來類比數組)。Go語言除了支援閉包外 ,沒有太多函數式的影子。

Go語言有以上每一流派的影子,但都只是把這些流派的最基礎的概念吸收 ,這些特性很基礎,很難作為一個流派的關鍵特徵來看。所以從編程範式上來說,個人認為Go語言不屬於以上 任何流派。如果非要說一個流派,Go語言類似C++,應該算“多範式”流派的。C++是主流語言中,幾乎是唯一 一門大力宣揚多範式編程理念的語言。C++主要支援的編程範式是過程式編程、物件導向編程、泛型程式設計(我 們上面沒有把泛型程式設計列入討論的流派之中)。C++對這些流派的主要特性支援都很完整,說“多範式”名副 其實。但Go不一樣的是,每個流派的特性支援都很基礎,這些特性只能稱之為功能,並沒有形成範式。

Go語言在吸收這些流派精華的基礎上,開創了自己獨特的編程風格:一種基於串連與組合的語言。

串連,指的是組件的耦合方式,也就是組件是如何被串聯起來的。組合,是形成綜合物件的基礎。連 接與組合都是語言中非常平凡的概念,但Go語言恰恰是在平凡之中見神奇。

讓我們從Unix談起。Go語 言與Unix、C語言有著極深的淵源。Go語言的領袖們參與甚至主導了Unix和C語言的設計。Ken Thompson 甚至 算得上Unix和C語言的鼻祖。Go語言亦深受Unix和C語言的設計哲學影響。

在Unix世界裡,組件就是應 用程式(app),每個app可大體抽象為:

輸入:stdin(標準輸入), params(命令列參數)

輸出:stdout(標準輸出)

協議:text (data stream)

不同的應用程式(app)如何串連?答案是:管道(pipeline)。在Unix世界中大家對這樣的東西已經很熟 悉了:

app1 params1 | app2 params2

通過管道(pipeline),可以將一個應用程式的輸 出(stdout)轉換為另一個應用程式的輸入(stdin)。更為神奇的一點,是這些應用程式是並存執行的。 app1每產生一段輸出,立即會被app2所處理。所以管道(pipeline)稱得上是最古老,同時也是極其優秀的並 行設施,簡單而強大。

需要注意的是,Unix世界中不同應用程式直接是鬆散耦合的。上遊app的輸出是 xml還是json,下遊app需要知曉,但並無任何強制的約束。同一輸出,不同的下遊app,對協議的理解甚至都 可能並不相同。例如,上遊app輸出一段xml文本,對於某個下遊app來說,是一顆dom樹,但對linecount程式 來說只是一個多行的文本,對於英文單詞詞頻統計程式來說,是一篇英文文章。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.