1. 程式人生 > >Go語言————1、初識GO語言

Go語言————1、初識GO語言

1.1 起源與發展

Go 語言起源 2007 年,並於 2009 年正式對外發布。它從 2009 年 9 月 21 日開始作為谷歌公司 20% 兼職專案,即相關員工利用 20% 的空餘時間來參與 Go 語言的研發工作。該專案的三位領導者均是著名的 IT 工程師:Robert Griesemer,參與開發 Java HotSpot 虛擬機器;Rob Pike,Go 語言專案總負責人,貝爾實驗室 Unix 團隊成員,參與的專案包括 Plan 9,Inferno 作業系統和 Limbo 程式語言;Ken Thompson,貝爾實驗室 Unix 團隊成員,C 語言、Unix 和 Plan 9 的創始人之一,與 Rob Pike 共同開發了 UTF-8 字符集規範。自 2008 年 1 月起,Ken Thompson 就開始研發一款以 C 語言為目標結果的編譯器來拓展 Go 語言的設計思想。

這是一個由計算機領域 “發明之父” 所組成的黃金團隊,他們對系統程式語言,作業系統和並行都有著非常深刻的見解


圖 1.1 Go 語言設計者:Griesemer、Thompson 和 Pike

在 2008 年年中,Go 語言的設計工作接近尾聲,一些員工開始以全職工作狀態投入到這個專案的編譯器和執行實現上。Ian Lance Taylor 也加入到了開發團隊中,並於 2008 年 5 月建立了一個 gcc 前端。

Russ Cox 加入開發團隊後著手語言和類庫方面的開發,也就是 Go 語言的標準包。在 2009 年 10 月 30 日,Rob Pike 以 Google Techtalk 的形式第一次向人們宣告了 Go 語言的存在。

直到 2009 年 11 月 10 日,開發團隊將 Go 語言專案以 BSD-style 授權(完全開源)正式公佈了 Linux 和 Mac OS X 平臺上的版本。Hector Chu 於同年 11 月 22 日公佈了 Windows 版本。

作為一個開源專案,Go 語言藉助開源社群的有生力量達到快速地發展,並吸引更多的開發者來使用並改善它。自該開源專案釋出以來,超過 200 名非谷歌員工的貢獻者對 Go 語言核心部分提交了超過 1000 個修改建議。在過去的 18 個月裡,又有 150 開發者貢獻了新的核心程式碼。這儼然形成了世界上最大的開源團隊,並使該專案躋身 Ohloh 前 2% 的行列。大約在 2011 年 4 月 10 日,谷歌開始抽調員工進入全職開發 Go 語言專案。開源化的語言顯然能夠讓更多的開發者參與其中並加速它的發展速度。Andrew Gerrand 在 2010 年加入到開發團隊中成為共同開發者與支持者。

在 Go 語言在 2010 年 1 月 8 日被 Tiobe(聞名於它的程式語言流行程度排名)宣佈為 “2009 年年度語言” 後,引起各界很大的反響。目前 Go 語言在這項排名中的最高記錄是在 2017 年 1 月創下的第13名,流行程度 2.325%。

時間軸:

  • 2007 年 9 月 21 日:雛形設計
  • 2009 年 11 月 10日:首次公開發布
  • 2010 年 1 月 8 日:當選 2009 年年度語言
  • 2010 年 5 月:谷歌投入使用
  • 2011 年 5 月 5 日:Google App Engine 支援 Go 語言

從 2010 年 5 月起,谷歌開始將 Go 語言投入到後端基礎設施的實際開發中,例如開發用於管理後端複雜環境的專案。有句話叫 “吃你自己的狗食”,這也體現了谷歌確實想要投資這門語言,並認為它是有生產價值的。

Go 語言的官方網站是 golang.org,這個站點採用 Python 作為前端,並且使用 Go 語言自帶的工具 godoc 執行在 Google App Engine 上來作為 Web 伺服器提供文字內容。在官網的首頁有一個功能叫做 Go Playground,是一個 Go 程式碼的簡單編輯器的沙盒,它可以在沒有安裝 Go 語言的情況下在你的瀏覽器中編譯並執行 Go,它提供了一些示例,其中包括國際慣例 “Hello, World!”。

Go 通過以下的 Logo 來展示它的速度,並以囊地鼠(Gopher)作為它的吉祥物。


圖1.2 Go 語言 Logo

谷歌郵件列表 golang-nuts 非常活躍,每天的討論和問題解答數以百計。

關於 Go 語言在 Google App Engine 的應用,這裡有一個單獨的郵件列表 google-appengine-go,不過 2 個郵件列表的討論內容並不是分得很清楚,都會涉及到相關的話題。go-lang.cat-v.org/ 是 Go 語言開發社群的資源站,irc.freenode.net 的#go-nuts 是官方的 Go IRC 頻道。

@golang 是 Go 語言在 Twitter 的官方帳號,大家一般使用 #golang 作為話題標籤。

Go 語言還有一個執行在 Google App Engine 上的 Go Tour,你也可以通過執行命令 go install go-tour.googlecode.com/hg/gotour 安裝到你的本地機器上。對於中文讀者,可以訪問該指南的 中文版本,或通過命令 go install https://bitbucket.org/mikespook/go-tour-zh/gotour 進行安裝。

1.2 語言的主要特性與發展的環境和影響因素

1.2.1 影響 Go 語言發展的早期程式語言

正如 “21 世紀的 C 語言” 這句話所說,Go 語言並不是憑空而造的,而是和 C++、Java 和 C# 一樣屬於 C 系。不僅如此,設計者們還汲取了其它程式語言的精粹部分融入到 Go 語言當中。

在宣告和包的設計方面,Go 語言受到 Pascal、Modula 和 Oberon 系語言的影響;在併發原理的設計上,Go 語言從同樣受到 Tony Hoare 的 CSP(通訊序列程序 Communicating Squential Processes)理論影響的 Limbo 和 Newsqueak 的實踐中借鑑了一些經驗,並使用了和 Erlang 類似的機制。

這是一門完全開源的程式語言,因為它使用 BSD 授權許可,所以任何人都可以進行商業軟體的開發而不需要支付任何費用。

儘管為了能夠讓目前主流的開發者們能夠對 Go 語言中的類 C 語言的語法感到非常親切而易於轉型,但是它在極大程度上簡化了這些語法,使得它們比 C/C++ 的語法更加簡潔和乾淨。同時,Go 語言也擁有一些動態語言的特性,這使得使用 Python 和 Ruby 的開發者們在使用 Go 語言的時候感覺非常容易上手。

下圖展示了一些其它程式語言對 Go 語言的影響:

圖 1.3 其它程式語言對 Go 語言的影響

1.2.2 為什麼要創造一門程式語言

  • C/C++ 的發展速度無法跟上計算機發展的腳步,十多年來也沒有出現一門與時代相符的主流系統程式語言,因此人們需要一門新的系統程式語言來彌補這個空缺,尤其是在計算機資訊時代。
  • 對比計算機效能的提升,軟體開發領域不被認為發展地足夠快或者比硬體發展更加成功(有許多專案均以失敗告終),同時應用程式的體積始終在不斷地擴大,這就迫切地需要一門具備更高層次概念的低階語言來突破現狀。
  • 在 Go 語言出現之前,開發者們總是面臨非常艱難的抉擇,究竟是使用執行速度快但是編譯速度並不理想的語言(如:C++),還是使用編譯速度較快但執行效率不佳的語言(如:.NET、Java),或者說開發難度較低但執行速度一般的動態語言呢?顯然,Go 語言在這 3 個條件之間做到了最佳的平衡:快速編譯,高效執行,易於開發。

1.2.3 Go 語言的發展目標

Go 語言的主要目標是將靜態語言的安全性和高效性與動態語言的易開發性進行有機結合,達到完美平衡,從而使程式設計變得更加有樂趣,而不是在艱難抉擇中痛苦前行。

因此,Go 語言是一門型別安全和記憶體安全的程式語言。雖然 Go 語言中仍有指標的存在,但並不允許進行指標運算。

Go 語言的另一個目標是對於網路通訊、併發和並行程式設計的極佳支援,從而更好地利用大量的分散式和多核的計算機,這一點對於谷歌內部的使用來說就非常重要了。設計者通過 goroutine 這種輕量級執行緒的概念來實現這個目標,然後通過 channel 來實現各個 goroutine 之間的通訊。他們實現了分段棧增長和 goroutine 線上程基礎上多路複用技術的自動化。

這個特性顯然是 Go 語言最強有力的部分,不僅支援了日益重要的多核與多處理器計算機,也彌補了現存程式語言在這方面所存在的不足。

Go 語言中另一個非常重要的特性就是它的構建速度(編譯和連結到機器程式碼的速度),一般情況下構建一個程式的時間只需要數百毫秒到幾秒。作為大量使用 C++ 來構建基礎設施的谷歌來說,無疑從根本上擺脫了 C++ 在構建速度上非常不理想的噩夢。這不僅極大地提升了開發者的生產力,同時也使得軟體開發過程中的程式碼測試環節更加緊湊,而不必浪費大量的時間在等待程式的構建上。

依賴管理是現今軟體開發的一個重要組成部分,但是 C 語言中“標頭檔案”的概念卻導致越來越多因為依賴關係而使得構建一個大型的專案需要長達幾個小時的時間。人們越來越需要一門具有嚴格的、簡潔的依賴關係分析系統從而能夠快速編譯的程式語言。這正是 Go 語言採用包模型的根本原因,這個模型通過嚴格的依賴關係檢查機制來加快程式構建的速度,提供了非常好的可量測性。

整個 Go 語言標準庫的編譯時間一般都在 20 秒以內,其它的常規專案也只需要半秒鐘的時間來完成編譯工作。這種閃電般的編譯速度甚至比編譯 C 語言或者 Fortran 更加快,使得編譯這一環節不再成為在軟體開發中困擾開發人員的問題。在這之前,動態語言將快速編譯作為自身的一大亮點,像 C++ 那樣的靜態語言一般都有非常漫長的編譯和連結工作。而同樣作為靜態語言的 Go 語言,通過自身優良的構建機制,成功地去除了這個弊端,使得程式的構建過程變得微不足道,擁有了像指令碼語言和動態語言那樣的高效開發的能力。

另外,Go 語言在執行速度方面也可以與 C/C++ 相提並論。

由於記憶體問題(通常稱為記憶體洩漏)長期以來一直伴隨著 C++ 的開發者們,Go 語言的設計者們認為記憶體管理不應該是開發人員所需要考慮的問題。因此儘管 Go 語言像其它靜態語言一樣執行原生代碼,但它依舊執行在某種意義上的虛擬機器,以此來實現高效快速的垃圾回收(使用了一個簡單的標記-清除演算法)。

儘管垃圾回收並不容易實現,但考慮這將是未來併發應用程式發展的一個重要組成部分,Go 語言的設計者們還是完成了這項艱難的任務。

Go 語言還能夠在執行時進行反射相關的操作。

使用 go install 能夠很輕鬆地對第三方包進行部署。

此外,Go 語言還支援呼叫由 C 語言編寫的海量庫檔案(第 3.9 節),從而能夠將過去開發的軟體進行快速遷移。

1.2.4 指導設計原則

Go語言通過減少關鍵字的數量(25 個)來簡化編碼過程中的混亂和複雜度。乾淨、整齊和簡潔的語法也能夠提高程式的編譯速度,因為這些關鍵字在編譯過程中少到甚至不需要符號表來協助解析。

這些方面的工作都是為了減少編碼的工作量,甚至可以與 Java 的簡化程度相比較。

Go 語言有一種極簡抽象藝術家的感覺,因為它只提供了一到兩種方法來解決某個問題,這使得開發者們的程式碼都非常容易閱讀和理解。眾所周知,程式碼的可讀性是軟體工程裡最重要的一部分( 譯者注:程式碼是寫給人看的,不是寫給機器看的 )。

這些設計理念沒有建立其它概念之上,所以並不會因為牽扯到一些概念而將某個概念複雜化,他們之間是相互獨立的。

Go 語言有一套完整的編碼規範,你可以在 Go 語言編碼規範 頁面進行檢視。

它不像 Ruby 那樣通過實現過程來定義編碼規範。作為一門具有明確編碼規範的語言,它要求可以採用不同的編譯器如 gc 和 gccgo(第 2.1 節)進行編譯工作,這對語言本身擁有更好的編碼規範起到很大幫助。

LALR 是 Go 語言的語法標準,你也可以在 src/cmd/internal/gc/go.y 中檢視到,這種語法標準在編譯時不需要符號表來協助解析。

1.2.5 語言的特性

Go 語言從本質上(程式和結構方面)來實現併發程式設計。

因為 Go 語言沒有類和繼承的概念,所以它和 Java 或 C++ 看起來並不相同。但是它通過介面(interface)的概念來實現多型性。Go 語言有一個清晰易懂的輕量級型別系統,在型別之間也沒有層級之說。因此可以說這是一門混合型的語言。

在傳統的面嚮物件語言中,使用面向物件程式設計技術顯得非常臃腫,它們總是通過複雜的模式來構建龐大的型別層級,這違背了程式語言應該提升生產力的宗旨。

函式是 Go 語言中的基本構件,它們的使用方法非常靈活。在第六章,我們會看到 Go 語言在函數語言程式設計方面的基本概念。

Go 語言使用靜態型別,所以它是型別安全的一門語言,加上通過構建到原生代碼,程式的執行速度也非常快。

作為強型別語言,隱式的型別轉換是不被允許的,記住一條原則:讓所有的東西都是顯式的。

Go 語言其實也有一些動態語言的特性(通過關鍵字 var),所以它對那些逃離 Java 和 .Net 世界而使用 Python、Ruby、PHP 和 JavaScript 的開發者們也具有很大的吸引力。

Go 語言支援交叉編譯,比如說你可以在執行 Linux 系統的計算機上開發執行下 Windows 下執行的應用程式。這是第一門完全支援 UTF-8 的程式語言,這不僅體現在它可以處理使用 UTF-8 編碼的字串,就連它的原始碼檔案格式都是使用的 UTF-8 編碼。Go 語言做到了真正的國際化!

1.2.6 語言的用途

Go 語言被設計成一門應用於搭載 Web 伺服器,儲存叢集或類似用途的巨型中央伺服器的系統程式語言。對於高效能分散式系統領域而言,Go 語言無疑比大多數其它語言有著更高的開發效率。它提供了海量並行的支援,這對於遊戲服務端的開發而言是再好不過了。

Go 語言一個非常好的目標就是實現所謂的複雜事件處理(CEP),這項技術要求海量並行支援,高度的抽象化和高效能。當我們進入到物聯網時代,CEP 必然會成為人們關注的焦點。

但是 Go 語言同時也是一門可以用於實現一般目標的語言,例如對於文字的處理,前端展現,甚至像使用指令碼一樣使用它。

值得注意的是,因為垃圾回收和自動記憶體分配的原因,Go 語言不適合用來開發對實時性要求很高的軟體。

越來越多的谷歌內部的大型分散式應用程式都開始使用 Go 語言來開發,例如谷歌地球的一部分程式碼就是由 Go 語言完成的。

如果你想知道一些其它組織使用Go語言開發的實際應用專案,你可以到 使用 Go 的組織 頁面進行檢視。出於隱私保護的考慮,許多公司的專案都沒有展示在這個頁面。我們將會在第 21 章討論到一個使用 Go 語言開發的大型儲存區域網路(SAN)案例。

在 Chrome 瀏覽器中內建了一款 Go 語言的編譯器用於本地客戶端(NaCl),這很可能會被用於在 Chrome OS 中執行 Go 語言開發的應用程式。

Go 語言可以在 Intel 或 ARM 處理器上執行,因此它也可以在安卓系統下執行,例如 Nexus 系列的產品。

在 Google App Engine 中使用 Go 語言:2011 年 5 月 5 日,官方釋出了用於開發執行在 Google App Engine 上的 Web 應用的 Go SDK,在此之前,開發者們只能選擇使用 Python 或者 Java。這主要是 David Symonds 和 Nigel Tao 努力的成果。目前最新的穩定版是基於 Go 1.4 的 SDK 1.9.18,於 2015 年 2 月 18 日釋出。當前 Go 語言的穩定版本是 Go 1.4.2。

1.2.7 關於特性缺失

許多能夠在大多數面嚮物件語言中使用的特性 Go 語言都沒有支援,但其中的一部分可能會在未來被支援。

  • 為了簡化設計,不支援函式過載和操作符過載
  • 為了避免在 C/C++ 開發中的一些 Bug 和混亂,不支援隱式轉換
  • Go 語言通過另一種途徑實現面向物件設計(第 10-11 章)來放棄類和型別的繼承
  • 儘管在介面的使用方面(第 11 章)可以實現類似變體型別的功能,但本身不支援變體型別
  • 不支援動態載入程式碼
  • 不支援動態連結庫
  • 不支援泛型
  • 通過 recover 和 panic 來替代異常機制(第 13.2-3 節)
  • 不支援斷言
  • 不支援靜態變數

關於 Go 語言開發團隊對於這些方面的討論,你可以通過 Go 常見問題 頁面檢視。

1.2.8 使用 Go 語言程式設計

如果你有其它語言的程式設計經歷(面向物件程式語言,如:Java、C#、Object-C、Python、Ruby),在你進入到 Go 語言的世界之後,你將會像迷戀你的 X 語言一樣無法自拔。Go 語言使用了與其它語言不同的設計模式,所以當你嘗試將你的X語言的程式碼遷移到 Go 語言時,你將會非常失望,所以你需要從頭開始,用 Go 的理念來思考。

如果你在至高點使用 Go 的理念來重新審視和分析一個問題,你通常會找到一個適用於 Go 語言的優雅的解決方案。

1.2.9 小結

這裡列舉一些 Go 語言的必殺技:

  • 簡化問題,易於學習
  • 記憶體管理,簡潔語法,易於使用
  • 快速編譯,高效開發
  • 高效執行
  • 併發支援,輕鬆駕馭
  • 靜態型別
  • 標準類庫,規範統一
  • 易於部署
  • 文件全面
  • 免費開源