讀古今文學網 > Go語言程序設計 > 引言 >

引言

本書介紹如何使用Go語言的語言特性以及標準庫中的常用包來進行地道的Go語言編程。同時,本書也設計成在學會 Go語言後依然有用的參考資料。為了實現這兩個目標,這本書覆蓋面非常廣,盡量保證每一章只涵蓋一個主題,各章之間會進行內容上的交叉引用。

從語言的設計精神來說,Go語言與 C 語言非常相似,是一門精小而高效的語言,它有便利的底層設施,如指針。不過Go語言還提供了許多只在高級或者非常高級的語言中才有的特性,如 Unicode 字符串、強大的內置數據結構、鴨子類型、垃圾收集和高層次的並發支持,使用通信而非常規的共享數據和鎖方式。另外,Go語言還提供了一個龐大且覆蓋面全的標準庫。

雖然所有的Go語言特性或者編程範式都會以完整可運行的示例來詳細講解,但是本書還是假設讀者有主流編程語言的經驗,比如C、C++、Java、Python或其他類似的語言。

要學好任何一門語言,使用它進行編程都是必經之路。為此,本書採用完全面向實戰的方式,鼓勵讀者親自去練習書中的例子,嘗試著去解決練習題中給出的問題,自己去寫程序,以獲得寶貴的實踐經驗。正如我以前寫的書一樣,本書中所引用的代碼片段都是「活代碼」。也就是說,這些代碼自動提取自.go源文件,並直接嵌入到提供給出版商的PDF文件中,故此不會有剪切和粘貼錯誤,可以直接運行。只要有可能,本書都會提供小而全的程序或者包來作為貼近實際應用場景的例子。本書的例子、練習和解決方案都可以從www.qtrac.eu/gobook.html這個網址獲得。

本書的主要目的是傳授Go語言本身,雖然我們使用了Go語言標準庫中的許多包,但不會試圖全都涉及。這並不是問題,因為本書向讀者提供了足夠的Go語言知識來使用任何標準庫中的包或者是任何第三方Go語言的包,當然還能夠創建自己的包。

為什麼是Go

Go語言始於2007年,當時只是Google內部的一個項目,其最初設計者是Robert Griesemer、Unix泰斗Rob Pike和Ken Thompson。2009年11月10日,Go語言以一個自由的開源許可方式公開亮相。Go語言由其原始設計者加上Russ Cox、Andrew Gerrand、Ian Lance Taylor以及其他許多人在內的一個Google團隊開發。Go語言採取一種開放的開發模式,吸引了許多來自世界各地的開發者為這門語言的發展貢獻力量。其中有些開發者獲得了非常好的聲望,因此他們也獲得了與Google員工一樣的代碼提交權限。此外,Go Dashboard這個網站(godashboard.appspot.com/project)也提供了許多第三方的Go語言包。

Go語言是近15年來出現的最令人興奮的新主流語言。它是第一個直接面向21世紀計算機和開發者的語言。

Go語言被設計為可高效地伸縮以便構建非常大的應用,並可在普通計算機上用幾秒鐘即完成編譯。快如閃電的編譯速度可能在一定程度上是因為語言的語法很容易解析,但更主要是因為它的依賴管理。如果文件app.go依賴於文件pkg1.go,而pkg1.go又依賴於pkg2.go,在傳統的編譯型語言中,app.go需要依賴於pkg1.go和pkg2.go目標文件。但在Go語言中,一切pkg2.go導出的內容都被緩存在pkg1.go的目標文件中,所以pkg1.go的目標文件足夠獨立構建 app.go。對於只有三個源文件的程序來說,這看不出什麼優劣,但對於有著大量依賴關係的大型應用程序來說,這樣做可以獲得巨大的編譯速度提升。

由於Go語言程序的構建是如此之快,因此它也適用一些本來應該使用腳本語言的場景(見「Go語言版Shebang腳本」,參見1.2節)。此外,Go語言可用於構建基於Google App Engine的Web應用程序。

Go語言使用了一種非常乾淨且易於理解的語法,避免了像老的語言如C++(發佈於1983年)或Java(發佈於1995年)一樣的複雜和冗長。Go語言是一種強靜態類型的語言,這在有些程序員看來是構建大型應用程序的必備特性。然而,使用 Go語言進行編程並不需要像使用別的靜態語言那樣打太多的字,這要歸功於 Go語言簡短的「聲明並初始化」的變量聲明語法(由於編譯器會推斷類型,因此並不需要顯式地寫明),以及它對鴨子類型強大而便捷的支持。

像C和C++這樣的語言,當涉及內存管理時需要程序員非常謹慎地面對,特別是對於並發程序,要跟蹤它們的內存分配簡直猶如噩夢,而這些本來可以交給計算機去做。近年來,C++在這方面用各種「智能」指針進行了很大的改善,但在線程庫方面還一直在追趕Java。通過使用垃圾收集器,Java減輕了程序員管理內存的負擔。雖然C++語言現在有一個標準的線程庫,但是C語言還只能使用第三方線程庫。然而,在C、C++或Java中編寫並發程序仍然需要相當地謹慎,以確保在恰當的時間正確地鎖定和解鎖資源。

Go編譯器和運行時系統會處理這些繁瑣的跟蹤問題。對於內存管理而言,Go語言提供了一個垃圾收集器,因此無需使用智能指針或者手動釋放內存。Go語言的並發機制基於計算機科學家C.A.R.Hoare提出的CSP(Communicating Sequential Processes)模型構建,這意味著許多並發的Go語言程序不需要加任何鎖[1]。此外,Go語言引入goroutine ——一種非常輕量級的進程,可以一次性大量創建,並可跨處理器和處理器核心自動進行負載平衡,以提供比老的基於線程的語言更細粒度的並發。事實上,因為Go語言的並發支持使用起來如此簡單和自然,移植單線程程序到Go時經常會發現轉為並發模型的機會大增,從而可以更充分地利用計算機資源。

Go語言是一門務實的語言,與語言的純淨度相比,它更關注語言效率以及為程序員帶來的便捷性。例如,Go語言的內置類型和用戶自定義的類型是不一樣的,因為前者可以高度優化,後者卻不能。Go語言也提供了兩個基本的內置集合類型:切片(slice,它的實際用途是為了提供變長功能的數組)和映射(map,也叫鍵值字典或散列表)。這些集合類型非常高效,並且在大多數情況下都能非常好地滿足需求。當然,Go語言也支持指針(它是一個完全編譯型的語言,因此在性能方面沒有虛擬機擋路),所以它可以輕鬆創建複雜的自定義類型,如平衡二叉樹。

雖然C語言僅支持過程式編程,而Java則強制要求程序員按照面向對象的方式來編程,但Go語言允許程序員使用最合適的編程範式來解決問題。Go語言可以被用做一個純粹的過程式編程語言,但對面向對像編程也支持得很好。不過,我們也會在後文看到,Go語言面向對像編程的方式與C++、Java或Python非常不同,它更容易使用且在形式上更加靈活。

就像C語言一樣,Go語言也不支持泛型(用C++的話來說就是模板)。然而,Go語言所提供的別的功能特性消除了對泛型支持的依賴。Go並不使用預處理器或者包含文件(這也是為什麼它編譯得如此之快的另一個原因),因此也無需像 C和C++那樣複製函數簽名。同時,因為沒有使用預處理器,程序的語義就無法在Go語言程序員背後悄悄變化,但這種情況在C和C++下使用#define時一不小心就會發生。

可以說,C++、Objective-C和Java都試圖成為更好的C語言(後者是間接地成為了更好的C++語言)。儘管Go語言乾淨而輕盈的語法容易讓人聯想到Python,Go語言的切片和映射也非常類似於Python的列表和字典,但Go語言也可以被認為試圖成為一個更好的C。然而,與任何其他語言相比,Go語言從語言本質上都更接近於C語言,並可以被認為保留了C語言的所有精華的同時試圖消除C語言中的缺陷,同時加入了許多強大而有用的獨有特性。

Go語言最初被構思為一門可充分利用分佈式系統以及多核聯網計算機優勢且適用於開發大型項目的編譯速度很快的系統級語言。現在,Go語言的觸角已經遠遠超出了原定的範疇,它正被用做一個具有高度生產力的通用編程語言。使用 Go語言開發和維護系統都讓人感覺是一種享受。

本書的結構

第1章開始講解如何建立和運行Go程序。這一章通過5個簡短的示例簡要介紹了Go語言的語法與特性,以及一些標準庫。每個例子都介紹了一些不同的特性。這一章主要是為了讓讀者嘗試一下Go語言,以此讓讀者感受一下學習Go語言需要學習的大致內容是什麼。(這一章章還講解了如何獲取和安裝Go語言環境。)

第2章至第7章更深入地講解了Go語言的方方面面。其中有三章專門講解了Go語言的內置數據類型:第2章涵蓋了標識符、布爾值和數值類型,第3章涵蓋了字符串,第4章涵蓋了Go語言內置的集合類型。

第5章描述並講解了Go語言的語句和控制結構,還解釋了如何創建和使用自定義的函數,最後展示了如何使用Go語言創建一個過程式的非並發程序。

第6章展示了如何在Go語言中進行面向對像編程。本章的內容包括可用於聚合和嵌入(委託)其他類型的結構體,可作為一個抽像類型的接口,以及如何在某些情況下產生類似繼承的效果。由於 Go語言中進行面向對像編程的方式可能與大多數讀者的經驗不同,這一章會給出幾個完整的例子並詳細講解,以確保讀者完全理解Go語言的面向對像編程方式。

第7掌講解了Go語言的並發特性,與面向對像編程一章相比,這一章給出了更多實例,以確保讀者對這些新的Go語言特性有透徹的瞭解。

第8章展示了如何讀取和寫入自定義的二進制文件、Go二進制(gob)文件、文本、JSON以及XML文件。(讀取和寫入文本文件的知識在第1章和後續幾章中都有所涉及,因為這些知識可以更易於提供一些有價值的示例和練習。)

本書的最後一章是第9章。這一章先展示了如何導入和使用標準庫包、自定義包以及第三方軟件包。它還展示如何對自定義的包進行文檔的自動提取、單元測試和性能基準測試。這一章的最後一節對Go編譯器(gc)提供的工具集以及Go語言的標準庫做了簡要的概述。

Go語言雖然小巧,但它同時也是一門功能豐富和強大表達能力(在語法結構、概念和編程習慣方面)的語言。本書的例子都符合良好的Go語言編程範式[2]。當然,這種做法也意味著有些概念出現時不會被當場解釋。但我們希望讀者相信,所有的概念都會在本書中進行解釋(當然,沒有當場解釋的內容都會以交叉引用的形式給出相應講解的位置)。

Go是一門迷人的語言,使用起來感覺非常好。學習Go語法和編程習慣並不會很難,但它的確引入了一些新穎的、對許多讀者來說可能不那麼熟悉的概念。這本書試圖給讀者概念上的突破,尤其是在面向對象的Go語言編程和並發Go語言編程方面。如果只閱讀那些定義良好卻非常簡要的文檔,讀者可能需要花費數周甚至數月的時間才能真正理解相關的知識。


[1].指不需要用戶主動加鎖,而不是指從內部實現來說沒有鎖。——譯者注

[2].這裡有一個例外:前面幾章中,即使通道只被當做單向通道使用,我們也總是將通道聲明為雙向的。從第7章開始,通道只被聲明為只有某一特殊的方向,這樣,這裡所說的Go語言風格用法也就講得通了。