在C語(yǔ)言和Unix操作系統(tǒng)發(fā)布40年后,肯·湯普森等貝爾實(shí)驗(yàn)室原班人馬終于推出了一門全新的編程語(yǔ)言,它就是Go語(yǔ)言。Go語(yǔ)言凝聚了該團(tuán)隊(duì)將近半個(gè)世紀(jì)對(duì)計(jì)算機(jī)工程的思考成果,被稱為互聯(lián)網(wǎng)時(shí)代的C語(yǔ)言。自Go語(yǔ)言第一次發(fā)布以來(lái),七牛云存儲(chǔ)團(tuán)隊(duì)就非常密切地關(guān)注這門語(yǔ)言的發(fā)展,并率先在七牛的產(chǎn)品中進(jìn)行大面積的應(yīng)用,而開發(fā)效率和系統(tǒng)穩(wěn)定性等客觀數(shù)據(jù)也在持續(xù)證明我們選擇Go語(yǔ)言的正確性。因此,我們迫不及待地希望向同行們分享這門語(yǔ)言,大家一起來(lái)享受Go語(yǔ)言所帶來(lái)的極大樂趣,也一起來(lái)促進(jìn)這門語(yǔ)言的發(fā)展吧!
《Go語(yǔ)言編程》首先概覽了Go語(yǔ)言的誕生和發(fā)展歷程,從面向過程編程特性入手介紹Go語(yǔ)言的基礎(chǔ)用法,讓有一定C語(yǔ)言基礎(chǔ)的讀者可以非常迅速地入門并開始上手用Go語(yǔ)言來(lái)解決實(shí)際問題,之后介紹了Go語(yǔ)言簡(jiǎn)潔卻又無(wú)比強(qiáng)大的面向?qū)ο缶幊烫匦院筒l(fā)編程能力,至此讀者已經(jīng)可以理解為什么Go語(yǔ)言是為互聯(lián)網(wǎng)時(shí)代而生的語(yǔ)言。從實(shí)用性角度出發(fā),本書還介紹了Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)和配套工具的用法,包括安全編程、網(wǎng)絡(luò)編程、工程管理工具等。對(duì)于希望對(duì)Go語(yǔ)言有更深入了解的讀者,我們也特別組織了一系列進(jìn)階話題,包括語(yǔ)言交互性、鏈接符號(hào)、goroutine機(jī)理和接口機(jī)制等!禛o語(yǔ)言編程》適合所有層次的開發(fā)者閱讀。
為什么我們需要一門新語(yǔ)言
編程語(yǔ)言已經(jīng)非常多,偏性能敏感的編譯型語(yǔ)言有 C、C++、Java、C#、Delphi和Objective-C等,偏快速業(yè)務(wù)開發(fā)的動(dòng)態(tài)解析型語(yǔ)言有 PHP、Python、Perl、Ruby、JavaScript和Lua等,面向特定領(lǐng)域的語(yǔ)言有 Erlang、R和MATLAB等,那么我們?yōu)槭裁葱枰?Go這樣一門新語(yǔ)言呢?
在2000年前的單機(jī)時(shí)代, C語(yǔ)言是編程之王。隨著機(jī)器性能的提升、軟件規(guī)模與復(fù)雜度的提高,Java逐步取代了C的位置。盡管看起來(lái) Java已經(jīng)深獲人心,但 Java編程的體驗(yàn)并未盡如人意。歷年來(lái)的編程語(yǔ)言排行榜(如圖 0-1所示)顯示, Java語(yǔ)言的市場(chǎng)份額在逐步下跌,并趨近于 C語(yǔ)言的水平,顯示了這門語(yǔ)言后勁不足。
圖0-1編程語(yǔ)言排行榜①
Go語(yǔ)言官方自稱,之所以開發(fā) Go語(yǔ)言,是因?yàn)?ldquo;近 10年來(lái)開發(fā)程序之難讓我們有點(diǎn)沮喪”。這一定位暗示了 Go語(yǔ)言希望取代 C和Java的地位,成為最流行的通用開發(fā)語(yǔ)言。 Go希望成為互聯(lián)網(wǎng)時(shí)代的 C語(yǔ)言。多數(shù)系統(tǒng)級(jí)語(yǔ)言(包括 Java和C#)的根本編程哲學(xué)來(lái)源于
——————————
、 據(jù)來(lái)源: http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html。
C++,將C++的面向?qū)ο筮M(jìn)一步發(fā)揚(yáng)光大。但是Go語(yǔ)言的設(shè)計(jì)者卻有不同的看法,他們認(rèn)為C++ 真的沒啥好學(xué)的,值得學(xué)習(xí)的是 C語(yǔ)言。C語(yǔ)言經(jīng)久不衰的根源是它足夠簡(jiǎn)單。因此, Go語(yǔ)言也要足夠簡(jiǎn)單!
那么,互聯(lián)網(wǎng)時(shí)代的 C語(yǔ)言需要考慮哪些關(guān)鍵問題呢?首先,并行與分布式支持。多核化和集群化是互聯(lián)網(wǎng)時(shí)代的典型特征。作為一個(gè)互聯(lián)網(wǎng)時(shí)代的C語(yǔ)言,必須要讓這門語(yǔ)言操作多核計(jì)算機(jī)與計(jì)算機(jī)集群如同操作單機(jī)一樣容易。其次,軟件工程支持。工程規(guī)模不斷擴(kuò)大是產(chǎn)業(yè)發(fā)展的必然趨勢(shì)。單機(jī)時(shí)代語(yǔ)言可以只關(guān)心問題本身的解決,而互聯(lián)網(wǎng)時(shí)代的 C語(yǔ)言還需要考慮軟件品質(zhì)保障和團(tuán)隊(duì)協(xié)作相關(guān)的話題。最后,編程哲學(xué)的重塑。計(jì)算機(jī)軟件經(jīng)歷了數(shù)十年的發(fā)展,形成了面向?qū)ο蟮榷喾N學(xué)術(shù)流派。什么才是最佳的編程實(shí)踐?作為互聯(lián)網(wǎng)時(shí)代的 C語(yǔ)言,需要回答這個(gè)問題。接下來(lái)我們來(lái)聊聊 Go語(yǔ)言在這些話題上是如何應(yīng)對(duì)的。
并發(fā)與分布式
多核化和集群化是互聯(lián)網(wǎng)時(shí)代的典型特征,那語(yǔ)言需要哪些特性來(lái)應(yīng)對(duì)這些特征呢?第一個(gè)話題是并發(fā)執(zhí)行的“執(zhí)行體”。執(zhí)行體是個(gè)抽象的概念,在操作系統(tǒng)層面有多個(gè)概念與之對(duì)應(yīng),比如操作系統(tǒng)自己掌管的進(jìn)程( process)、進(jìn)程內(nèi)的線程( thread)以及進(jìn)程內(nèi)的協(xié)程
。╟oroutine,也叫輕量級(jí)線程)。多數(shù)語(yǔ)言在語(yǔ)法層面并不直接支持協(xié)程,而通過庫(kù)的方式支持的協(xié)程的功能也并不完整,比如僅僅提供協(xié)程的創(chuàng)建、銷毀與切換等能力。如果在這樣的協(xié)程中調(diào)用一個(gè)同步 IO操作,比如網(wǎng)絡(luò)通信、本地文件讀寫,都會(huì)阻塞其他的并發(fā)執(zhí)行協(xié)程,從而無(wú)法真正達(dá)到協(xié)程本身期望達(dá)到的目標(biāo)。
Go語(yǔ)言在語(yǔ)言級(jí)別支持協(xié)程,叫 goroutine。Go語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供的所有系統(tǒng)調(diào)用( syscall)操作,當(dāng)然也包括所有同步 IO操作,都會(huì)出讓 CPU給其他goroutine,這讓事情變得非常簡(jiǎn)單。我們對(duì)比一下Java和Go,近距離觀摩下兩者對(duì)“執(zhí)行體”的支持。
為了簡(jiǎn)化,我們?cè)跇永惺褂玫氖?Java標(biāo)準(zhǔn)庫(kù)中的線程,而不是協(xié)程,具體代碼如下:
public class MyThread implements Runnable {
String arg;
public MyThread(String a) { arg = a; }
public void run() { // ... }
public static void main(String[] args) { new Thread(new MyThread(“”test“”)).start(); // ...
}
}
相同功能的代碼,在 Go語(yǔ)言中是這樣的:
func run(arg string) {
// ...
}
func main() {
go run(“”test“”)
...
}
對(duì)比非常鮮明。我相信你已經(jīng)明白為什么 Go語(yǔ)言會(huì)叫 Go語(yǔ)言了:Go語(yǔ)言獻(xiàn)給這個(gè)時(shí)代最好的禮物,就是加了 go這個(gè)關(guān)鍵字。當(dāng)然也有人會(huì)說,叫 Go語(yǔ)言是因?yàn)樗?Google出的。好吧,這也是個(gè)不錯(cuò)的閑聊主題。
第二個(gè)話題是“執(zhí)行體間的通信”。執(zhí)行體間的通信包含幾個(gè)方式:
·執(zhí)行體之間的互斥與同步
·執(zhí)行體之間的消息傳遞
先說·執(zhí)行體之間的互斥與同步·。當(dāng)執(zhí)行體之間存在共享資源(一般是共享內(nèi)存)時(shí),為保證內(nèi)存訪問邏輯的確定性,需要對(duì)訪問該共享資源的相關(guān)執(zhí)行體進(jìn)行互斥。當(dāng)多個(gè)執(zhí)行體之間的邏輯存在時(shí)序上的依賴時(shí),也往往需要在執(zhí)行體之間進(jìn)行同步。互斥與同步是執(zhí)行體間最基礎(chǔ)的交互方式。
多數(shù)語(yǔ)言在庫(kù)層面提供了線程間的互斥與同步支持,那么協(xié)程之間的互斥與同步呢?呃,不好意思,沒有。事實(shí)上多數(shù)語(yǔ)言標(biāo)準(zhǔn)庫(kù)中連協(xié)程都是看不到的。
再說·執(zhí)行體之間的消息傳遞·。在并發(fā)編程模型的選擇上,有兩個(gè)流派,一個(gè)是共享內(nèi)存模型,一個(gè)是消息傳遞模型。多數(shù)傳統(tǒng)語(yǔ)言選擇了前者,少數(shù)語(yǔ)言選擇后者,其中選擇·消息傳遞模型·的最典型代表是 Erlang語(yǔ)言。業(yè)界有專門的術(shù)語(yǔ)叫“ Erlang風(fēng)格的并發(fā)模型”,其主體思想是兩點(diǎn):一是“輕量級(jí)的進(jìn)程( Erlang中‘進(jìn)程’這個(gè)術(shù)語(yǔ)就是我們上面說的‘執(zhí)行體’)”,二是“消息乃進(jìn)程間通信的唯一方式”。當(dāng)執(zhí)行體之間需要相互傳遞消息時(shí),通常需要基于一個(gè)消息隊(duì)列(message queue)或者進(jìn)程郵箱( process mail box)這樣的設(shè)施進(jìn)行通信。
Go語(yǔ)言推薦采用“ Erlang風(fēng)格的并發(fā)模型”的編程范式,盡管傳統(tǒng)的“共享內(nèi)存模型”仍然被保留,允許適度地使用。在 Go語(yǔ)言中內(nèi)置了消息隊(duì)列的支持,只不過它叫通道( channel)。兩個(gè)goroutine之間可以通過通道來(lái)進(jìn)行交互。
軟件工程
單機(jī)時(shí)代的語(yǔ)言可以只關(guān)心問題本身的解決,但是隨著工程規(guī)模的不斷擴(kuò)大,軟件復(fù)雜度的不斷增加,軟件工程也成為語(yǔ)言設(shè)計(jì)層面要考慮的重要課題。多數(shù)軟件需要一個(gè)團(tuán)隊(duì)共同去完成,在團(tuán)隊(duì)協(xié)作的過程中,人們需要建立統(tǒng)一的交互語(yǔ)言來(lái)降低溝通的成本。規(guī)范化體現(xiàn)在多個(gè)層面,如:
·代碼風(fēng)格規(guī)范
·錯(cuò)誤處理規(guī)范
·包管理
·契約規(guī)范(接口)
·單元測(cè)試規(guī)范
·功能開發(fā)的流程規(guī)范
Go語(yǔ)言很可能是第一個(gè)將代碼風(fēng)格強(qiáng)制統(tǒng)一的語(yǔ)言,例如 Go語(yǔ)言要求 public的變量必須以大寫字母開頭,private變量則以小寫字母開頭,這種做法不僅免除了public、private關(guān)鍵字,更重要的是統(tǒng)一了命名風(fēng)格。
另外,Go語(yǔ)言對(duì) { }應(yīng)該怎么寫進(jìn)行了強(qiáng)制,比如以下風(fēng)格是正確的:
if expression { ... }
但下面這個(gè)寫法就是錯(cuò)誤的:
if expression { ... }
而C和Java語(yǔ)言中則對(duì)花括號(hào)的位置沒有任何要求。哪種更有利,這個(gè)見仁見智。但很顯然的是,所有的 Go代碼的花括號(hào)位置肯定是非常統(tǒng)一的。最有意思的其實(shí)還是 Go語(yǔ)言首創(chuàng)的錯(cuò)誤處理規(guī)范:
f, err := os.Open(filename)
if err != nil { log.Println(“”Open file failed:““, err) return
} defer f.Close() ... // 操作已經(jīng)打開的 f文件
這里有兩個(gè)關(guān)鍵點(diǎn)。其一是 defer關(guān)鍵字。 defer語(yǔ)句的含義是不管程序是否出現(xiàn)異常,均在函數(shù)退出時(shí)自動(dòng)執(zhí)行相關(guān)代碼。在上面的例子中,正是因?yàn)橛辛?defer,才使得無(wú)論后續(xù)是否會(huì)出現(xiàn)異常,都可以確保文件被正確關(guān)閉。其二是 Go語(yǔ)言的函數(shù)允許返回多個(gè)值。大多數(shù)函數(shù)的最后一個(gè)返回值會(huì)為 error類型,以在錯(cuò)誤情況下返回詳細(xì)信息。 error類型只是一個(gè)系統(tǒng)內(nèi)置的interface,如下:
type error interface { Error() string }
有了error類型,程序出現(xiàn)錯(cuò)誤的邏輯看起來(lái)就相當(dāng)統(tǒng)一。在Java中,你可能這樣寫代碼來(lái)保證資源正確釋放:
Connection conn = ...;
try { Statement stmt = ...; try {
ResultSet rset = ...; try {
... // 正常代碼 } finally {
rset.close();
} } finally {
stmt.close();
} } finally {
conn.close(); }
完成同樣的功能,相應(yīng)的 Go代碼只需要寫成這樣:
conn := ... defer conn.Close()
stmt := ... defer stmt.Close()
rset := ... defer rset.Close() ... // 正常代碼
對(duì)比兩段代碼, Go語(yǔ)言處理錯(cuò)誤的優(yōu)勢(shì)顯而易見。當(dāng)然,其實(shí) Go語(yǔ)言帶給我們的驚喜還有很多,后續(xù)有機(jī)會(huì)我們可以就某個(gè)更具體的話題詳細(xì)展開來(lái)談一談。
編程哲學(xué)
計(jì)算機(jī)軟件經(jīng)歷了數(shù)十年的發(fā)展,形成了多種學(xué)術(shù)流派,有面向過程編程、面向?qū)ο缶幊、函?shù)式編程、面向消息編程等,這些思想究竟孰優(yōu)孰劣,眾說紛紜。
C語(yǔ)言是純過程式的,這和它產(chǎn)生的歷史背景有關(guān)。 Java語(yǔ)言則是激進(jìn)的面向?qū)ο笾髁x推崇者,典型表現(xiàn)是它不能容忍體系里存在孤立的函數(shù)。而 Go語(yǔ)言沒有去否認(rèn)任何一方,而是用批判吸收的眼光,將所有編程思想做了一次梳理,融合眾家之長(zhǎng),但時(shí)刻警惕特性復(fù)雜化,極力維持語(yǔ)言特性的簡(jiǎn)潔,力求小而精。
從編程范式的角度來(lái)說, Go語(yǔ)言是變革派,而不是改良派。對(duì)于C++、Java和C#等語(yǔ)言為代表的面向?qū)ο螅?OO)思想體系,Go語(yǔ)言總體來(lái)說持保守態(tài)度,有限吸收。首先,Go語(yǔ)言反對(duì)函數(shù)和操作符重載( overload),而C++、Java和C#都允許出現(xiàn)同名函數(shù)或操作符,只要它們的參數(shù)列表不同。雖然重載解決了一小部分面向?qū)ο缶幊蹋?OOP)的問題,但
同樣給這些語(yǔ)言帶來(lái)了極大的負(fù)擔(dān)。而 Go語(yǔ)言有著完全不同的設(shè)計(jì)哲學(xué),既然函數(shù)重載帶來(lái)了負(fù)擔(dān),并且這個(gè)特性并不對(duì)解決任何問題有顯著的價(jià)值,那么 Go就不提供它。其次,Go語(yǔ)言支持類、類成員方法、類的組合,但反對(duì)繼承,反對(duì)虛函數(shù)( virtual function)和虛函數(shù)重載。確切地說, Go也提供了繼承,只不過是采用了組合的文法來(lái)提供:
type Foo struct { Base ...
}
func (foo *Foo) Bar() { ... }
再次,Go語(yǔ)言也放棄了構(gòu)造函數(shù)( constructor)和析構(gòu)函數(shù)(destructor)。由于Go語(yǔ)言中沒有虛函數(shù),也就沒有 vptr,支持構(gòu)造函數(shù)和析構(gòu)函數(shù)就沒有太大的價(jià)值。本著“如果一個(gè)特性并不對(duì)解決任何問題有顯著的價(jià)值,那么 Go就不提供它”的原則,構(gòu)造函數(shù)和析構(gòu)函數(shù)就這樣被Go語(yǔ)言的作者們干掉了。
在放棄了大量的 OOP特性后,Go語(yǔ)言送上了一份非常棒的禮物:接口( interface)。你可能會(huì)說,除了 C這么原始的語(yǔ)言外,還有什么語(yǔ)言沒有接口呢?是的,多數(shù)語(yǔ)言都提供接口,但它們的接口都不同于 Go語(yǔ)言的接口。
Go語(yǔ)言中的接口與其他語(yǔ)言最大的一點(diǎn)區(qū)別是它的非侵入性。在 C++、Java和C#中,為了實(shí)現(xiàn)一個(gè)接口,你需要從該接口繼承,具體代碼如下:
class Foo implements IFoo { // Java文法 ... }
class Foo : public IFoo { // C++文法 ... }
IFoo* foo = new Foo;
在Go語(yǔ)言中,實(shí)現(xiàn)類的時(shí)候無(wú)需從接口派生,具體代碼如下:
type Foo struct { // Go 文法 ... }
var foo IFoo = new(Foo)
只要Foo實(shí)現(xiàn)了接口IFoo要求的所有方法,就實(shí)現(xiàn)了該接口,可以進(jìn)行賦值。 Go語(yǔ)言的非侵入式接口,看似只是做了很小的文法調(diào)整,實(shí)則影響深遠(yuǎn)。其一,Go語(yǔ)言的標(biāo)準(zhǔn)庫(kù)再也不需要繪制類庫(kù)的繼承樹圖。你只需要知道這個(gè)類實(shí)現(xiàn)了哪些
方法,每個(gè)方法是啥含義就足夠了。其二,不用再糾結(jié)接口需要拆得多細(xì)才合理,比如我們實(shí)現(xiàn)了 File類,它有下面這些方法:
前言:為什么我們需要一門新語(yǔ)言
Read(buf []byte) (n int, err error) Write(buf []byte) (n int, err error) Seek(off int64, whence int) (pos int64, err error) Close() error
那么,到底是應(yīng)該定義一個(gè) IFile接口,還是應(yīng)該定義一系列的 IReader、IWriter、 ISeeker和ICloser接口,然后讓File從它們派生好呢?事實(shí)上,脫離了實(shí)際的用戶場(chǎng)景,討論這兩個(gè)設(shè)計(jì)哪個(gè)更好并無(wú)意義。問題在于,實(shí)現(xiàn) File類的時(shí)候,我怎么知道外部會(huì)如何用它呢?
其三,不用為了實(shí)現(xiàn)一個(gè)接口而專門導(dǎo)入一個(gè)包,而目的僅僅是引用其中的某個(gè)接口的定義。在Go語(yǔ)言中,只要兩個(gè)接口擁有相同的方法列表,那么它們就是等同的,可以相互賦值,如對(duì)于以下兩個(gè)接口,第一個(gè)接口:
package one
type ReadWriter interface {
Read(buf [] byte) (n int, err error)
Write(buf [] byte) (n int, err error)
}
第二個(gè)接口:
package two
type IStream interface {
Write(buf [] byte) (n int, err error)
Read(buf [] byte) (n int, err error)
}
這里我們定義了兩個(gè)接口,一個(gè)叫 one.ReadWriter,一個(gè)叫 two.IStream,兩者都定義了Read()和Write()方法,只是定義的次序相反。 one.ReadWriter先定義了 Read()再定義 Write(),而two.IStream反之。
在Go語(yǔ)言中,這兩個(gè)接口實(shí)際上并無(wú)區(qū)別,因?yàn)椋?br /> ·任何實(shí)現(xiàn)了 one.ReadWriter接口的類,均實(shí)現(xiàn)了 two.IStream;
·任何one.ReadWriter接口對(duì)象可賦值給 two.IStream,反之亦然;
·在任何地方使用 one.ReadWriter接口,與使用 two.IStream并無(wú)差異。所以在Go語(yǔ)言中,為了引用另一個(gè)包中的接口而導(dǎo)入這個(gè)包的做法是不被推薦的。因?yàn)槎嘁靡粋(gè)外部的包,就意味著更多的耦合。
除了OOP外,近年出現(xiàn)了一些小眾的編程哲學(xué), Go語(yǔ)言對(duì)這些思想亦有所吸收。例如, Go語(yǔ)言接受了函數(shù)式編程的一些想法,支持匿名函數(shù)與閉包。再如, Go語(yǔ)言接受了以 Erlang語(yǔ)言為代表的面向消息編程思想,支持 goroutine和通道,并推薦使用消息而不是共享內(nèi)存來(lái)進(jìn)行并發(fā)編程?傮w來(lái)說, Go語(yǔ)言是一個(gè)非,F(xiàn)代化的語(yǔ)言,精小但非常強(qiáng)大。
小結(jié)
在十余年的技術(shù)生涯中,我接觸過、使用過、喜愛過不同的編程語(yǔ)言,但總體而言, Go語(yǔ)言的出現(xiàn)是最讓我興奮的事情。我個(gè)人對(duì)未來(lái) 10年編程語(yǔ)言排行榜的趨勢(shì)判斷如下:
□·Java語(yǔ)言的份額繼續(xù)下滑,并最終被 C和Go語(yǔ)言超越;
□·C語(yǔ)言將長(zhǎng)居編程榜第二的位置,并有望在 Go取代Java前重獲語(yǔ)言榜第一的寶座;
□·Go語(yǔ)言最終會(huì)取代 Java,居于編程榜之首。
由七牛云存儲(chǔ)團(tuán)隊(duì)編著的這本書將盡可能展現(xiàn)出 Go語(yǔ)言的迷人魅力。希望本書能夠讓更多人理解這門語(yǔ)言,熱愛這門語(yǔ)言,讓這門優(yōu)秀的語(yǔ)言能夠落到實(shí)處,把程序員從以往繁雜的語(yǔ)言細(xì)節(jié)中解放出來(lái),集中精力開發(fā)更加優(yōu)秀的系統(tǒng)軟件。
許式偉 2012年3月7日
許式偉,七牛云存儲(chǔ)CEO,曾任盛大創(chuàng)新院資深研究員、金山軟件技術(shù)總監(jiān)、WPS Office 2005首席架構(gòu)師。開源愛好者,發(fā)布過包括WINX、TPL等十余個(gè)C++開源項(xiàng)目,擁有超過15年的C/C++開發(fā)經(jīng)驗(yàn)。在接觸Go語(yǔ)言后即可被其大道至簡(jiǎn)、少即是多的設(shè)計(jì)哲學(xué)所傾倒。七牛云存儲(chǔ)是國(guó)內(nèi)第一個(gè)吃螃蟹的團(tuán)隊(duì),核心服務(wù)完全采用Go語(yǔ)言實(shí)現(xiàn)。
呂桂華,七牛云存儲(chǔ)聯(lián)合創(chuàng)始人,曾在金山軟件、盛大游戲等公司擔(dān)任架構(gòu)師和部門經(jīng)理等職務(wù),在企業(yè)級(jí)系統(tǒng)和大型網(wǎng)游平臺(tái)領(lǐng)域有較多涉獵。擁有十余年的C/C++大型項(xiàng)目開發(fā)經(jīng)驗(yàn),也曾在Java和.NET平臺(tái)上探索多年。同樣被Go語(yǔ)言的魅力所吸引而不可自拔,希望能為推廣這門優(yōu)秀的語(yǔ)言盡自己的綿薄之力。
第1章 初識(shí)Go語(yǔ)言
1.1 語(yǔ)言簡(jiǎn)史
1.2 語(yǔ)言特性
1.2.1 自動(dòng)垃圾回收
1.2.2 更豐富的內(nèi)置類型
1.2.3 函數(shù)多返回值
1.2.4 錯(cuò)誤處理
1.2.5 匿名函數(shù)和閉包
1.2.6 類型和接口
1.2.7 并發(fā)編程
1.2.8 反射
1.2.9 語(yǔ)言交互性
1.3 第一個(gè)Go程序
1.3.1 代碼解讀
1.3.2 編譯環(huán)境準(zhǔn)備
1.3.3 編譯程序
1.4 開發(fā)工具選擇
1.5 工程管理
1.6 問題追蹤和調(diào)試
1.6.1 打印日志
1.6.2 GDB調(diào)試
1.7 如何尋求幫助
1.7.1 郵件列表
1.7.2 網(wǎng)站資源
1.8 小結(jié)
第2章 順序編程
2.1 變量
2.1.1 變量聲明
2.1.2 變量初始化
2.1.3 變量賦值
2.1.4 匿名變量
2.2 常量
2.2.1 字面常量
2.2.2 常量定義
2.2.3 預(yù)定義常量
2.2.4 枚舉
2.3 類型
2.3.1 布爾類型
2.3.2 整型
2.3.3 浮點(diǎn)型
2.3.4 復(fù)數(shù)類型
2.3.5 字符串
2.3.6 字符類型
2.3.7 數(shù)組
2.3.8 數(shù)組切片
2.3.9 map
2.4 流程控制
2.4.1 條件語(yǔ)句
2.4.2 選擇語(yǔ)句
2.4.3 循環(huán)語(yǔ)句
2.4.4 跳轉(zhuǎn)語(yǔ)句
2.5 函數(shù)
2.5.1 函數(shù)定義
2.5.2 函數(shù)調(diào)用
2.5.3 不定參數(shù)
2.5.4 多返回值
2.5.5 匿名函數(shù)與閉包
2.6 錯(cuò)誤處理
2.6.1 error接口
2.6.2 defer
2.6.3 panic()和recover()
2.7 完整示例
2.7.1 程序結(jié)構(gòu)
2.7.2 主程序
2.7.3 算法實(shí)現(xiàn)
2.7.4 主程序
2.7.5 構(gòu)建與執(zhí)行
2.8 小結(jié)
第3章 面向?qū)ο缶幊?br />3.1 類型系統(tǒng)
3.1.1 為類型添加方法
3.1.2 值語(yǔ)義和引用語(yǔ)義
3.1.3 結(jié)構(gòu)體
3.2 初始化
3.3 匿名組合
3.4 可見性
3.5 接口
3.5.1 其他語(yǔ)言的接口
3.5.2 非侵入式接口
3.5.3 接口賦值
3.5.4 接口查詢
3.5.5 類型查詢
3.5.6 接口組合
3.5.7 Any類型
3.6 完整示例
3.6.1 音樂庫(kù)
3.6.2 音樂播放
3.6.3 主程序
3.6.4 構(gòu)建運(yùn)行
3.6.5 遺留問題
3.7 小結(jié)
第4章 并發(fā)編程
4.1 并發(fā)基礎(chǔ)
4.2 協(xié)程
4.3 goroutine
4.4 并發(fā)通信
4.5 channel
4.5.1 基本語(yǔ)法
4.5.2 select
4.5.3 緩沖機(jī)制
4.5.4 超時(shí)機(jī)制
4.5.5 channel的傳遞
4.5.6 單向channel
4.5.7 關(guān)閉channel
4.6 多核并行化
4.7 出讓時(shí)間片
4.8 同步
4.8.1 同步鎖
4.8.2 全局唯一性操作
4.9 完整示例
4.9.1 簡(jiǎn)單IPC框架
4.9.2 中央服務(wù)器
4.9.3 主程序
4.9.4 運(yùn)行程序
4.10 小結(jié)
第5章 網(wǎng)絡(luò)編程
5.1 Socket編程
5.1.1 Dial()函數(shù)
5.1.2 ICMP示例程序
5.1.3 TCP示例程序
5.1.4 更豐富的網(wǎng)絡(luò)通信
5.2 HTTP編程
5.2.1 HTTP客戶端
5.2.2 HTTP服務(wù)端
5.3 RPC編程
5.3.1 Go語(yǔ)言中的RPC支持與處理
5.3.2 Gob簡(jiǎn)介
5.3.3 設(shè)計(jì)優(yōu)雅的RPC接口
5.4 JSON處理
5.4.1 編碼為JSON格式
5.4.2 解碼JSON數(shù)據(jù)
5.4.3 解碼未知結(jié)構(gòu)的JSON數(shù)據(jù)
5.4.4 JSON的流式讀寫
5.5 網(wǎng)站開發(fā)
5.5.1 最簡(jiǎn)單的網(wǎng)站程序
5.5.2 net/http包簡(jiǎn)介
5.5.3 開發(fā)一個(gè)簡(jiǎn)單的相冊(cè)網(wǎng)站
5.6 小結(jié)
第6章 安全編程
6.1 數(shù)據(jù)加密
6.2 數(shù)字簽名
6.3 數(shù)字證書
6.4 PKI體系
6.5 Go語(yǔ)言的哈希函數(shù)
6.6 加密通信
6.6.1 加密通信流程
6.6.2 支持HTTPS的Web服務(wù)器
6.6.3 支持HTTPS的文件服務(wù)器
6.6.4 基于SSL/TLS的ECHO程序
6.7 小結(jié)
第7章 工程管理
7.1 Go命令行工具
7.2 代碼風(fēng)格
7.2.1 強(qiáng)制性編碼規(guī)范
7.2.2 非強(qiáng)制性編碼風(fēng)格建議
7.3 遠(yuǎn)程import支持
7.4 工程組織
7.4.1 GOPATH
7.4.2 目錄結(jié)構(gòu)
7.5 文檔管理
7.6 工程構(gòu)建
7.7 跨平臺(tái)開發(fā)
7.7.1 交叉編譯
7.7.2 Android支持
7.8 單元測(cè)試
7.9 打包分發(fā)
7.10 小結(jié)
第8章 開發(fā)工具
8.1 選擇開發(fā)工具
8.2 gedit
8.2.1 語(yǔ)法高亮
8.2.2 編譯環(huán)境
8.3 Vim
8.4 Eclipse
8.5 Notepad++
8.5.1 語(yǔ)法高亮
8.5.2 編譯環(huán)境
8.6 LiteIDE
8.7 小結(jié)
第9章 進(jìn)階話題
9.1 反射
9.1.1 基本概念
9.1.2 基本用法
9.1.3 對(duì)結(jié)構(gòu)的反射操作
9.2 語(yǔ)言交互性
9.2.1 類型映射
9.2.2 字符串映射
9.2.3 C程序
9.2.4 函數(shù)調(diào)用
9.2.5 編譯Cgo
9.3 鏈接符號(hào)
9.4 goroutine機(jī)理
9.4.1 協(xié)程
9.4.2 協(xié)程的C語(yǔ)言實(shí)現(xiàn)
9.4.3 協(xié)程庫(kù)概述
9.4.4 任務(wù)
9.4.5 任務(wù)調(diào)度
9.4.6 上下文切換
9.4.7 通信機(jī)制
9.5 接口機(jī)理
9.5.1 類型賦值給接口
9.5.2 接口查詢
9.5.3 接口賦值
附錄A