Go程序设计语言导读
生活随笔
收集整理的這篇文章主要介紹了
Go程序设计语言导读
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
前 言 The Go Programming Language “Go是一種開源的程序設計語言,它意在使得人們能夠方便地構建簡單、可靠、高效的軟件。”(來自Go官網golang.org) Go在2007年9月形成構想,并于2009年11月發布,其發明人是Robert Griesemer、Rob Pike和Ken Thompson,這幾位都任職于Google。該語言及其配套工具集使得編譯和執行既富有表達力又高效,而且使得程序員能夠輕松寫出可靠、健壯的程序。 Go和C從表面上看起來相似,而且和C一樣,它也是專業程序員使用的一種工具,兼有事半功倍之效。但是Go遠不止是C的一種升級版本。基于多種其他語言,它取其精華,去其糟粕。它實現并發功能的設施是全新的、高效的,實現數據抽象和面向對象的途徑是極其靈活的。它還實現了自動化的內存管理,或稱為垃圾回收。 Go特別適用于構建基礎設施類軟件(如網絡服務器),以及程序員使用的工具和系統等。但它的的確確是一種通用語言,而且在諸多領域(如圖像處理、移動應用和機器學習)中都能發現它的身影。它在很多場合下用于替換無類型的腳本語言,這是由于它兼顧了表達力和安全性:Go程序通常比動態語言程序運行速度要快,由于意料之外的類型錯誤而導致崩潰的情形更是少得多。 Go是個開源項目,所以其編譯器、庫和工具的源代碼是人人皆可免費取得的。來自全世界的社區都在積極地向這個項目貢獻代碼。Go的運行環境包括類UNIX系統——Linux、FreeBSD、OpenBSD和Mac OS X,還有Plan 9和Microsoft Windows。只要在其中一個環境中寫了一個程序,那么基本上不加修改它就可以運行在其他環境中。 本書旨在幫助讀者立刻開始使用Go,以及熟練掌握這門語言,并充分地利用Go的語言特性和標準庫來撰寫清晰的、符合習慣用法的、高效的程序。 Go的起源 和生物學物種一樣,成功的語言會繁衍后代,這些后代語言會從它們的祖先那里汲取各種優點;有時候,語言間的“混血”會產生異常強大的力量;在一些罕見情況下,某個重大的語言特性也可能憑空出現而并無先例。通過考察語言間的影響,我們可以學得不少知識,比如語言為什么會變成這個樣子,以及它適合用于哪些環境,等等。 下圖展示了更早出現的程序設計語言對Go產生的最重要影響。 Go有時會稱為“類C語言”或“21世紀的C”。從C中,Go繼承了表達式語法、控制流語句、基本數據類型、按值調用的形參傳遞和指針,但比這些更重要的是,繼承了C所強調的要點:程序要編譯成高效的機器碼,并自然地與所處的操作系統提供的抽象機制相配合。 可是,Go的家譜中還有其他祖先。產生主要影響的是由Niklaus Wirth設計的、以Pascal為發端的一個語言支流。Modula-2啟發了包概念。Oberon消除了模塊接口文件和模塊實現文件之間的差異。Oberon-2影響了包、導入和聲明的語法,并提供了方法聲明的語法。
Go的另一支世系祖先——它使得Go相對于當下的程序設計語言顯得卓然不群,是在貝爾實驗室開發的一系列名不見經傳的研究用語言。這些語言都受到了通信順序進程(Communicating Sequential Process,CSP)的啟發,CSP由Tony Hoare于1978年在發表的關于并發性基礎的開創性論文中提出。在CSP中,程序就是一組無共享狀態進程的并行組合,進程間的通信和同步采用通道完成。不過,Hoare提出的CSP是一種形式語言,僅用于描述并發性的基本概念,并不是一種用來撰寫可執行程序的程序設計語言。 Rob Pike等人開始動手做一些實驗,嘗試把CSP實現為真正的語言。第一種這樣的語言稱為Squeak(“和鼠類溝通的語言”),它是一種用于處理鼠標和鍵盤事件的語言,其中具有靜態創建的通道。緊接著它的是Newsqueak,它具有類C的語句和表達式語法,以及類Pascal的類型記法。它是一種純粹的函數式語言,具有垃圾回收功能,同樣也以管理鍵盤、鼠標和窗口事件為目標。通道變成了“一等”值(first-class value),它可以動態創建并用變量存儲。 Plan 9操作系統將這些思想都納入一種稱為Alef的語言中。Alef嘗試將Newsqueak改造成一種可用的系統級程序設計語言,但垃圾回收功能的缺失使得它在處理并發性時捉襟見肘。 Go中的其他結構也會不時顯示出某些并非來自祖先的基因。例如,iota多多少少有點APL的影子,而嵌套函數的詞法作用域則來自Scheme(以及由之而來的大部分語言)。在Go語言中,也可以發現全新的變異。Go中新穎的slice不僅為動態數組提供了高效的隨機訪問功能,還允許舊式鏈表的復雜共享機制。另外,defer語句也是Go中新引入的。 Go項目 所有的程序設計語言都反映了其發明者的程序設計哲理,其中相當大的一部分是對于此前語言已知缺點的應對措施。Go這個項目也誕生于挫敗感,這種挫敗感來源于Google的若干復雜性激增的軟件系統。(而且這個問題絕非Google所獨有的。) “復雜性是以乘積方式增長的。”Rob Pike如是說。為了修復某個問題,一點點地將系統的某個部分變得更加復雜,這不可避免地也給其他部分增加了復雜性。在不斷要求增加系統功能、選項和配置,以及快速發布的壓力之下,簡單性往往被忽視了(盡管長期來看,簡單性才是好軟件的不二法門)。 要實現簡單性,就要求在項目的一開始就濃縮思想的本質,并在項目的整個生命周期制定更具體的準則,以分辨出哪些變化是好的,哪些是壞的或致命的。只要足夠努力,好的變化就既可以實現目的,又能夠不損害Fred Brooks所謂軟件設計上的“概念完整性”。壞的變化就做不到這一點,而致命的變化則會犧牲“簡單性”去換得淺薄的“方便性”。但是,只有通過設計上的簡單性,系統才能在增長過程中保持穩定、安全和自洽。 Go項目不僅包括該語言本身及其工具和標準庫,還有決不能忽視的一點,就是它保持極端簡單性的行為文化。在高級語言中,Go出現得較晚,因而有一定后發優勢,它的基礎部分實現得不錯:有垃圾回收、包系統、一等公民函數、詞法作用域、系統調用接口,還有默認用UTF-8編碼的不可變字符串。但相對來說,它的語言特性不多,而且不太會增加新特性了。比如,它沒有隱式數值類型強制轉換,沒有構造或析構函數,沒有運算符重載,沒有形參默認值,沒有繼承,沒有泛型,沒有異常,沒有宏,沒有函數注解,沒有線程局部存儲。這門語言成熟而且穩定,并且保證兼容更早版本:在舊版本的Go語言中寫的程序,可以在新版本的編譯器和標準庫下編譯與運行。 Go的類型系統足可以使程序員避免在動態語言中會無意犯下的絕大多數錯誤,但相對而言,它在帶類型的語言中又算是類型系統比較簡單的。其實現方法有時候會導致類型框架林立卻彼此孤立的“無類型”程序設計風格,并且Go程序員在類型方面不會像C++或Haskell程序員那樣走極端——反復表達類型安全性以證明語言是基于類型的。但在實際工作中,Go卻能為程序員提供只有強類型的系統才能實現的安全性和運行時性能,而不讓程序員承擔其復雜性。 Go提倡充分利用當代計算機系統設計,尤其強調局部性的重要意義。其內置數據類型和大多數庫數據結構都經過仔細設計,力求以自然方式工作,而不要求顯式的初始化或隱式的構造函數。這么一來,隱藏在代碼中的內存分配和內存寫入就大大減少了。Go中的聚合類型(結構體和數組)都以直接方式持有其元素,與使用間接字段的語言相比,它需要更少的存儲空間以及更少的分配操作和指針間接尋址操作。正如前面提到的那樣,由于現代計算機都是并行工作的,因此Go具有基于CSP的并行特性。Go還提供了變長棧來運行其輕量級線程,或稱為goroutine。這個棧初始時非常小,所以創建一個goroutine的成本極低,創建100萬個也完全可以接受。 Go標準庫常常稱作“自帶電池的語言”,它提供了清晰的構件,以及用于I/O、文本處理、圖形、加密、網絡、分布式應用的API,而且對許多標準文件格式和協議都提供了支持。Go的庫和工具充分地尊重慣例,避免了配置和解釋,從而簡化了程序邏輯,提高了多種多樣的Go程序之間的相似性,使得它更容易學習和掌握。采用go工具構建的項目,僅使用文件和標識符的名字(在極少情況下使用特殊注釋),就可以推斷出一個項目使用的所有庫、可執行文件、測試、性能基準、示例、平臺相關變體,以及文檔。Go的源代碼中就包含了構建的規格說明。? 本書結構 我們假定你已用一兩種其他語言編過程序,可能是像C、C++或Java那樣的編譯型語言,也可能是像Python、Ruby或JavaScript那樣的解釋型語言,所以本書不會像針對一個零基礎的初學者那樣事無巨細地講述所有內容。表面上的語法大體雷同,變量、常量、表達式、控制流和函數也一樣。 第1章是關于Go的基礎結構的綜述,通過十幾個完成日常任務(包括讀寫文件、格式化文本、創建圖像,以及在Internet客戶端和服務器之間通信)的程序來介紹這門語言。 第2章講述Go程序的組成元素——聲明、變量、新類型、包和文件,以及作用域。第3章討論數值、布爾量、字符串、常量,還解釋如何處理Unicode。第4章描述復合類型,即使用簡單類型構造的類型,形式有數組、map、結構體,還有slice(Go中動態列表的實現)。第5章概述函數,并討論錯誤處理、宕機(panic)和恢復(recover),以及defer語句。 可以看出,第1~5章是基礎性的,其內容是任何主流命令式語言都有的。Go的語法和風格可能與其他語言有所不同,但大多數程序員都能很快掌握這些內容。余下的章節重點討論Go語言中與慣常做法有一定區別的內容,包括方法、接口、并發、包、測試和反射。 Go以一種不同尋常的方式來詮釋面向對象程序設計。它沒有類繼承,甚至沒有類。較復雜的對象行為是通過較簡單的對象組合(而非繼承)完成的。方法可以關聯到任何用戶定義的類型,而不一定是結構體。具體類型和抽象類型(即接口)之間的關系是隱式的,所以一個具體類型可能會實現該類型設計者沒有意識到其存在的接口。第6章講述方法,第7章講述接口。 第8章介紹Go的并發性處理途徑,它基于CSP思想,采用goroutine和通道實現。第9章則討論并發性中基于共享變量的一些傳統話題。 第10章討論包,也就是組織庫的機制。該章也說明如何高效地利用go工具,僅僅這個工具,就提供了編譯、測試、性能基準測試、程序格式化、文檔,以及完成許多其他任務的功能。 第11章討論測試,在這里Go采取了顯著的輕量級途徑,避免了重重抽象的框架,轉而使用簡單的庫和工具。測試庫提供了一個基礎,在其之上根據需要可以構建更復雜的抽象。 第12章討論反射,即程序在執行期間考察自身表示方式的能力。反射是一種強大的工具,不過要慎重使用它,該章通過演示如何用它來實現某些重要的Go庫,解釋了如何統籌兼顧。第13章解釋低級程序設計的細節(它運用unsafe包來繞過Go的類型系統),以及什么時候適合這樣做。 每章都配以一定數量的練習,可以用來測試你對Go的理解,或者探索對書中示例的擴展和變形。 除了最簡單的示例代碼以外,書中所有的示例代碼都可以從gopl.io網站的公開Git倉庫下載。每個示例以其包的導入路徑開頭和命名,從而能夠方便地使用go get命令獲取、構建和安裝。你需要選取一個目錄作為你的Go工作空間,并使GOPATH環境變量指向它。在必要時,go工具會創建該目錄。例如:
要運行這些例子,至少需要使用1.5版本的Go語言。
如果你的計算機上的go工具版本太舊或者缺失,請按https://golang.org/doc/install上的步驟操作。 更多信息來源 關于Go的更多信息,最好的來源就是Go的官方網站:https://golang.org。其中列出了文檔供讀者訪問,包括Go程序設計語言規范、標準包等。其中還列出Go語言教程,指導如何撰寫Go程序,以及如何撰寫好的Go程序,還有大量在線文本和視頻資源,這些都是本書的主要補充資源。位于blog.golang.org的Go博客發布的是關于Go的最好文章,內容涉及該語言當下的狀態、未來的計劃、會議方面的報告,還有Go相關的大量話題的深度解讀。 Go官網在線訪問最有用的一個方面(這也是紙質書的一個令人遺憾的限制),就是提供了從描述Go程序的網頁上直接運行的能力。這種功能由位于play.golang.org的Go訓練場(Playground)提供,也可以嵌入其他頁面,比如golang.org的首頁,或者由godoc工具提供的文檔頁面。 訓練場為讀者對簡短的程序執行簡單的實驗提供了方便,有助于讀者檢驗自己對語法、語義和庫包的理解,并且它在很多方面取代了其他語言中的讀取–求值–輸出循環(Read-Eval-Print Loop,REPL)。它的永久URL對于共享Go代碼段、報告bug或提出建議都很有用。 在訓練場的基礎之上,位于tour.golang.org的Go Tour就是一系列簡短的交互式課程(內容是Go語言的基礎思想和結構),也是學習整門語言的系統資源。 訓練場和Go Tour的主要缺點在于它只允許導入標準庫,并且很多庫特性(比如網絡庫)都出于可操作性或安全原因限制使用。而要編譯和運行每個程序,都要求Internet連接。所以,欲進行更詳盡的實驗,需要在本機上運行Go程序。幸運的是,下載過程相當簡單,從golang.org獲取Go的安裝版本并開始撰寫和運行你自己的Go程序,用不了幾分鐘。 由于Go是個開源項目,因此你可以從https://golang.org/pkg上在線讀取標準庫中的任何類型或函數的代碼,每個供下載的版本都同樣包含這些代碼。請使用這些代碼來弄明白某些程序的運行原理、回答關于程序細節的問題,也可以用它們來學一學專家是如何寫出一流的Go代碼的。 致謝 Go團隊的核心成員Rob Pike和Russ Cox仔細通讀了初稿數次,他們從遣詞造句到整體結構都對本書提出了重要的建議。在準備本書的日語版時,柴田芳樹所做的貢獻大大超過了他負擔的義務,他的火眼金睛發現了英語版中的上下文不一致性,以及代碼中的錯誤。非常感謝Brian Goetz、Corey Kosak、Arnold Robbins、Josh Bleecher Snyder以及Peter Weinberger對全書初稿進行徹底的審查并提出批判性的建議。 感謝Sameer Ajmani、Ittai Balaban、David Crawshaw、Billy Donohue、Jonathan Feinberg、Andrew Gerrand、Robert Griesemer、John Linderman、Minux Ma、Bryan Mills、Bala Natarajan、Cosmos Nicolaou、Paul Staniforth、Nigel Tao以及Howard Trickey提供的諸多有用建議。也感謝David Brailsford和Raph Levien的排版建議。 Addison-Wesley出版社的編輯Greg Doench策劃了本書,而且一直不斷地給予幫助。Addison-Wesley的制作團隊——John Fuller、Dayna Isley、Julie Nahil、Chuti Prasertsith以及Barbara Wood——非常杰出,給予作者大量的支持。 Alan Donovan想要感謝Google的Sameer Ajmani、Chris Demetriou、Walt Drummond以及Reid Tatge讓他騰出時間來寫作這本書,還要感謝Stephen Donovan的建議和及時的鼓勵。最重要的是,感謝他的妻子Leila Kazemi無限的熱情和長期的支持,諒解了他在家庭生活中的疏忽。 Brian Kernighan對他的朋友和同事深表謝意,他們對Kernighan花費了很長時間以通俗易懂的語言寫作本書表現出了極大的耐心和理解。尤其是他的妻子Meg,她為Kernighan的寫作以及太多的其他事務提供了不懈的支持。
目 錄
第1章 入門 ? 1.1 hello,world ? 1.2 命令行參數 ? 1.3 找出重復行 ? 1.4 GIF動畫 ? 1.5 獲取一個URL
1.6 并發獲取多個URL
1.7 一個Web服務器 ? 1.8 其他內容 ? 第2章 程序結構 ? 2.1 名稱 ? 2.2 聲明 ? 2.3 變量 ? 2.4 賦值 ? 2.5 類型聲明 ? 2.6 包和文件 ? 2.7 作用域 ? 第3章 基本數據 ? 3.1 整數 ? 3.2 浮點數 ? 3.3 復數? 3.4 布爾值 ? 3.5 字符串 ? 3.6 常量 ? 第4章 復合數據類型 ?61 4.1 數組 ?61 4.2 slice ?63 4.2.1 append函數 ?66 4.2.2 slice就地修改 ?69 4.3 map ?71 4.4 結構體 ?76 4.4.1 結構體字面量 ?78 4.4.2 結構體比較 ?80 4.4.3 結構體嵌套和匿名成員 ?80 4.5 JSON ?82 4.6 文本和HTML模板 ?87 第5章 函數 ?92 5.1 函數聲明 ?92 5.2 遞歸 ?93 5.3 多返回值 ?96 5.4 錯誤 ?98 5.4.1 錯誤處理策略 ?99 5.4.2 文件結束標識 ?101 5.5 函數變量 ?102 5.6 匿名函數 ?104 5.7 變長函數 ?110 5.8 延遲函數調用 ?111 5.9 宕機 ?115 5.10 恢復 ?118 第6章 方法 ?120 6.1 方法聲明 ?120 6.2 指針接收者的方法 ?122 6.3 通過結構體內嵌組成類型 ?124 6.4 方法變量與表達式 ?127 6.5 示例:位向量 ?128 6.6 封裝 ?130 第7章 接口 ?133 7.1 接口即約定 ?133 7.2 接口類型 ?135 7.3 實現接口 ?136 7.4 使用flag.Value來解析參數 ?139 7.5 接口值 ?141 7.6 使用sort.Interface來排序 ?144 7.7 http.Handler接口 ?148 7.8 error接口 ?152 7.9 示例:表達式求值器 ?154 7.10 類型斷言 ?160 7.11 使用類型斷言來識別錯誤 ?161 7.12 通過接口類型斷言來查詢特性 ?162 7.13 類型分支 ?164 7.14 示例:基于標記的XML解析 ?166 7.15 一些建議 ?168 第8章 goroutine和通道 ?170 8.1 goroutine ?170 8.2 示例:并發時鐘服務器 ?171 8.3 示例:并發回聲服務器 ?174 8.4 通道 ?176 8.4.1 無緩沖通道 ?177 8.4.2 管道 ?178 8.4.3 單向通道類型 ?180 8.4.4 緩沖通道 ?181 8.5 并行循環 ?183 8.6 示例:并發的Web爬蟲 ?187 8.7 使用select多路復用 ?190 8.8 示例:并發目錄遍歷 ?192 8.9 取消 ?195 8.10 示例:聊天服務器 ?198 第9章 使用共享變量實現并發 ?201 9.1 競態 ?201 9.2 互斥鎖:sync.Mutex ?205 9.3 讀寫互斥鎖:sync.RWMutex ?208 9.4 內存同步 ?208 9.5 延遲初始化:sync.Once ?210 9.6 競態檢測器 ?212 9.7 示例:并發非阻塞緩存 ?212 9.8 goroutine與線程 ?218 9.8.1 可增長的棧 ?219 9.8.2 goroutine調度 ?219 9.8.3 GOMAXPROCS ?219 9.8.4 goroutine沒有標識 ?220 第10章 包和go工具 ?221 10.1 引言 ?221 10.2 導入路徑 ?221 10.3 包的聲明 ?222 10.4 導入聲明 ?223 10.5 空導入 ?223 10.6 包及其命名 ?225 10.7 go工具 ?226 10.7.1 工作空間的組織 ?227 10.7.2 包的下載 ?228 10.7.3 包的構建 ?229 10.7.4 包的文檔化 ?231 10.7.5 內部包 ?232 10.7.6 包的查詢 ?233 第11章 測試 ?235 11.1 go test工具 ?235 11.2 Test函數 ?236 11.2.1 隨機測試 ?239 11.2.2 測試命令 ?240 11.2.3 白盒測試 ?242 11.2.4 外部測試包 ?245 11.2.5 編寫有效測試 ?246 11.2.6 避免脆弱的測試 ?247 11.3 覆蓋率 ?248 11.4 Benchmark函數 ?250 11.5 性能剖析 ?252 11.6 Example函數 ?254 第12章 反射 ?256 12.1 為什么使用反射 ?256 12.2 reflect.Type和reflect.Value ?257 12.3 Display:一個遞歸的值顯示器 ?259 12.4 示例:編碼S表達式 ?263 12.5 使用reflect.Value來設置值 ?266 12.6 示例:解碼S表達式 ?268 12.7 訪問結構體字段標簽 ?271 12.8 顯示類型的方法 ?273 12.9 注意事項 ?274 第13章 低級編程 ?276 13.1 unsafe.Sizeof、Alignof 和Offsetof ?276 13.2 unsafe.Pointer ?278 13.3 示例:深度相等 ?280 13.4 使用cgo調用C代碼 ?282 13.5 關于安全的注意事項 ?286
Go的另一支世系祖先——它使得Go相對于當下的程序設計語言顯得卓然不群,是在貝爾實驗室開發的一系列名不見經傳的研究用語言。這些語言都受到了通信順序進程(Communicating Sequential Process,CSP)的啟發,CSP由Tony Hoare于1978年在發表的關于并發性基礎的開創性論文中提出。在CSP中,程序就是一組無共享狀態進程的并行組合,進程間的通信和同步采用通道完成。不過,Hoare提出的CSP是一種形式語言,僅用于描述并發性的基本概念,并不是一種用來撰寫可執行程序的程序設計語言。 Rob Pike等人開始動手做一些實驗,嘗試把CSP實現為真正的語言。第一種這樣的語言稱為Squeak(“和鼠類溝通的語言”),它是一種用于處理鼠標和鍵盤事件的語言,其中具有靜態創建的通道。緊接著它的是Newsqueak,它具有類C的語句和表達式語法,以及類Pascal的類型記法。它是一種純粹的函數式語言,具有垃圾回收功能,同樣也以管理鍵盤、鼠標和窗口事件為目標。通道變成了“一等”值(first-class value),它可以動態創建并用變量存儲。 Plan 9操作系統將這些思想都納入一種稱為Alef的語言中。Alef嘗試將Newsqueak改造成一種可用的系統級程序設計語言,但垃圾回收功能的缺失使得它在處理并發性時捉襟見肘。 Go中的其他結構也會不時顯示出某些并非來自祖先的基因。例如,iota多多少少有點APL的影子,而嵌套函數的詞法作用域則來自Scheme(以及由之而來的大部分語言)。在Go語言中,也可以發現全新的變異。Go中新穎的slice不僅為動態數組提供了高效的隨機訪問功能,還允許舊式鏈表的復雜共享機制。另外,defer語句也是Go中新引入的。 Go項目 所有的程序設計語言都反映了其發明者的程序設計哲理,其中相當大的一部分是對于此前語言已知缺點的應對措施。Go這個項目也誕生于挫敗感,這種挫敗感來源于Google的若干復雜性激增的軟件系統。(而且這個問題絕非Google所獨有的。) “復雜性是以乘積方式增長的。”Rob Pike如是說。為了修復某個問題,一點點地將系統的某個部分變得更加復雜,這不可避免地也給其他部分增加了復雜性。在不斷要求增加系統功能、選項和配置,以及快速發布的壓力之下,簡單性往往被忽視了(盡管長期來看,簡單性才是好軟件的不二法門)。 要實現簡單性,就要求在項目的一開始就濃縮思想的本質,并在項目的整個生命周期制定更具體的準則,以分辨出哪些變化是好的,哪些是壞的或致命的。只要足夠努力,好的變化就既可以實現目的,又能夠不損害Fred Brooks所謂軟件設計上的“概念完整性”。壞的變化就做不到這一點,而致命的變化則會犧牲“簡單性”去換得淺薄的“方便性”。但是,只有通過設計上的簡單性,系統才能在增長過程中保持穩定、安全和自洽。 Go項目不僅包括該語言本身及其工具和標準庫,還有決不能忽視的一點,就是它保持極端簡單性的行為文化。在高級語言中,Go出現得較晚,因而有一定后發優勢,它的基礎部分實現得不錯:有垃圾回收、包系統、一等公民函數、詞法作用域、系統調用接口,還有默認用UTF-8編碼的不可變字符串。但相對來說,它的語言特性不多,而且不太會增加新特性了。比如,它沒有隱式數值類型強制轉換,沒有構造或析構函數,沒有運算符重載,沒有形參默認值,沒有繼承,沒有泛型,沒有異常,沒有宏,沒有函數注解,沒有線程局部存儲。這門語言成熟而且穩定,并且保證兼容更早版本:在舊版本的Go語言中寫的程序,可以在新版本的編譯器和標準庫下編譯與運行。 Go的類型系統足可以使程序員避免在動態語言中會無意犯下的絕大多數錯誤,但相對而言,它在帶類型的語言中又算是類型系統比較簡單的。其實現方法有時候會導致類型框架林立卻彼此孤立的“無類型”程序設計風格,并且Go程序員在類型方面不會像C++或Haskell程序員那樣走極端——反復表達類型安全性以證明語言是基于類型的。但在實際工作中,Go卻能為程序員提供只有強類型的系統才能實現的安全性和運行時性能,而不讓程序員承擔其復雜性。 Go提倡充分利用當代計算機系統設計,尤其強調局部性的重要意義。其內置數據類型和大多數庫數據結構都經過仔細設計,力求以自然方式工作,而不要求顯式的初始化或隱式的構造函數。這么一來,隱藏在代碼中的內存分配和內存寫入就大大減少了。Go中的聚合類型(結構體和數組)都以直接方式持有其元素,與使用間接字段的語言相比,它需要更少的存儲空間以及更少的分配操作和指針間接尋址操作。正如前面提到的那樣,由于現代計算機都是并行工作的,因此Go具有基于CSP的并行特性。Go還提供了變長棧來運行其輕量級線程,或稱為goroutine。這個棧初始時非常小,所以創建一個goroutine的成本極低,創建100萬個也完全可以接受。 Go標準庫常常稱作“自帶電池的語言”,它提供了清晰的構件,以及用于I/O、文本處理、圖形、加密、網絡、分布式應用的API,而且對許多標準文件格式和協議都提供了支持。Go的庫和工具充分地尊重慣例,避免了配置和解釋,從而簡化了程序邏輯,提高了多種多樣的Go程序之間的相似性,使得它更容易學習和掌握。采用go工具構建的項目,僅使用文件和標識符的名字(在極少情況下使用特殊注釋),就可以推斷出一個項目使用的所有庫、可執行文件、測試、性能基準、示例、平臺相關變體,以及文檔。Go的源代碼中就包含了構建的規格說明。? 本書結構 我們假定你已用一兩種其他語言編過程序,可能是像C、C++或Java那樣的編譯型語言,也可能是像Python、Ruby或JavaScript那樣的解釋型語言,所以本書不會像針對一個零基礎的初學者那樣事無巨細地講述所有內容。表面上的語法大體雷同,變量、常量、表達式、控制流和函數也一樣。 第1章是關于Go的基礎結構的綜述,通過十幾個完成日常任務(包括讀寫文件、格式化文本、創建圖像,以及在Internet客戶端和服務器之間通信)的程序來介紹這門語言。 第2章講述Go程序的組成元素——聲明、變量、新類型、包和文件,以及作用域。第3章討論數值、布爾量、字符串、常量,還解釋如何處理Unicode。第4章描述復合類型,即使用簡單類型構造的類型,形式有數組、map、結構體,還有slice(Go中動態列表的實現)。第5章概述函數,并討論錯誤處理、宕機(panic)和恢復(recover),以及defer語句。 可以看出,第1~5章是基礎性的,其內容是任何主流命令式語言都有的。Go的語法和風格可能與其他語言有所不同,但大多數程序員都能很快掌握這些內容。余下的章節重點討論Go語言中與慣常做法有一定區別的內容,包括方法、接口、并發、包、測試和反射。 Go以一種不同尋常的方式來詮釋面向對象程序設計。它沒有類繼承,甚至沒有類。較復雜的對象行為是通過較簡單的對象組合(而非繼承)完成的。方法可以關聯到任何用戶定義的類型,而不一定是結構體。具體類型和抽象類型(即接口)之間的關系是隱式的,所以一個具體類型可能會實現該類型設計者沒有意識到其存在的接口。第6章講述方法,第7章講述接口。 第8章介紹Go的并發性處理途徑,它基于CSP思想,采用goroutine和通道實現。第9章則討論并發性中基于共享變量的一些傳統話題。 第10章討論包,也就是組織庫的機制。該章也說明如何高效地利用go工具,僅僅這個工具,就提供了編譯、測試、性能基準測試、程序格式化、文檔,以及完成許多其他任務的功能。 第11章討論測試,在這里Go采取了顯著的輕量級途徑,避免了重重抽象的框架,轉而使用簡單的庫和工具。測試庫提供了一個基礎,在其之上根據需要可以構建更復雜的抽象。 第12章討論反射,即程序在執行期間考察自身表示方式的能力。反射是一種強大的工具,不過要慎重使用它,該章通過演示如何用它來實現某些重要的Go庫,解釋了如何統籌兼顧。第13章解釋低級程序設計的細節(它運用unsafe包來繞過Go的類型系統),以及什么時候適合這樣做。 每章都配以一定數量的練習,可以用來測試你對Go的理解,或者探索對書中示例的擴展和變形。 除了最簡單的示例代碼以外,書中所有的示例代碼都可以從gopl.io網站的公開Git倉庫下載。每個示例以其包的導入路徑開頭和命名,從而能夠方便地使用go get命令獲取、構建和安裝。你需要選取一個目錄作為你的Go工作空間,并使GOPATH環境變量指向它。在必要時,go工具會創建該目錄。例如:
要運行這些例子,至少需要使用1.5版本的Go語言。
如果你的計算機上的go工具版本太舊或者缺失,請按https://golang.org/doc/install上的步驟操作。 更多信息來源 關于Go的更多信息,最好的來源就是Go的官方網站:https://golang.org。其中列出了文檔供讀者訪問,包括Go程序設計語言規范、標準包等。其中還列出Go語言教程,指導如何撰寫Go程序,以及如何撰寫好的Go程序,還有大量在線文本和視頻資源,這些都是本書的主要補充資源。位于blog.golang.org的Go博客發布的是關于Go的最好文章,內容涉及該語言當下的狀態、未來的計劃、會議方面的報告,還有Go相關的大量話題的深度解讀。 Go官網在線訪問最有用的一個方面(這也是紙質書的一個令人遺憾的限制),就是提供了從描述Go程序的網頁上直接運行的能力。這種功能由位于play.golang.org的Go訓練場(Playground)提供,也可以嵌入其他頁面,比如golang.org的首頁,或者由godoc工具提供的文檔頁面。 訓練場為讀者對簡短的程序執行簡單的實驗提供了方便,有助于讀者檢驗自己對語法、語義和庫包的理解,并且它在很多方面取代了其他語言中的讀取–求值–輸出循環(Read-Eval-Print Loop,REPL)。它的永久URL對于共享Go代碼段、報告bug或提出建議都很有用。 在訓練場的基礎之上,位于tour.golang.org的Go Tour就是一系列簡短的交互式課程(內容是Go語言的基礎思想和結構),也是學習整門語言的系統資源。 訓練場和Go Tour的主要缺點在于它只允許導入標準庫,并且很多庫特性(比如網絡庫)都出于可操作性或安全原因限制使用。而要編譯和運行每個程序,都要求Internet連接。所以,欲進行更詳盡的實驗,需要在本機上運行Go程序。幸運的是,下載過程相當簡單,從golang.org獲取Go的安裝版本并開始撰寫和運行你自己的Go程序,用不了幾分鐘。 由于Go是個開源項目,因此你可以從https://golang.org/pkg上在線讀取標準庫中的任何類型或函數的代碼,每個供下載的版本都同樣包含這些代碼。請使用這些代碼來弄明白某些程序的運行原理、回答關于程序細節的問題,也可以用它們來學一學專家是如何寫出一流的Go代碼的。 致謝 Go團隊的核心成員Rob Pike和Russ Cox仔細通讀了初稿數次,他們從遣詞造句到整體結構都對本書提出了重要的建議。在準備本書的日語版時,柴田芳樹所做的貢獻大大超過了他負擔的義務,他的火眼金睛發現了英語版中的上下文不一致性,以及代碼中的錯誤。非常感謝Brian Goetz、Corey Kosak、Arnold Robbins、Josh Bleecher Snyder以及Peter Weinberger對全書初稿進行徹底的審查并提出批判性的建議。 感謝Sameer Ajmani、Ittai Balaban、David Crawshaw、Billy Donohue、Jonathan Feinberg、Andrew Gerrand、Robert Griesemer、John Linderman、Minux Ma、Bryan Mills、Bala Natarajan、Cosmos Nicolaou、Paul Staniforth、Nigel Tao以及Howard Trickey提供的諸多有用建議。也感謝David Brailsford和Raph Levien的排版建議。 Addison-Wesley出版社的編輯Greg Doench策劃了本書,而且一直不斷地給予幫助。Addison-Wesley的制作團隊——John Fuller、Dayna Isley、Julie Nahil、Chuti Prasertsith以及Barbara Wood——非常杰出,給予作者大量的支持。 Alan Donovan想要感謝Google的Sameer Ajmani、Chris Demetriou、Walt Drummond以及Reid Tatge讓他騰出時間來寫作這本書,還要感謝Stephen Donovan的建議和及時的鼓勵。最重要的是,感謝他的妻子Leila Kazemi無限的熱情和長期的支持,諒解了他在家庭生活中的疏忽。 Brian Kernighan對他的朋友和同事深表謝意,他們對Kernighan花費了很長時間以通俗易懂的語言寫作本書表現出了極大的耐心和理解。尤其是他的妻子Meg,她為Kernighan的寫作以及太多的其他事務提供了不懈的支持。
目 錄
第1章 入門 ? 1.1 hello,world ? 1.2 命令行參數 ? 1.3 找出重復行 ? 1.4 GIF動畫 ? 1.5 獲取一個URL
1.6 并發獲取多個URL
1.7 一個Web服務器 ? 1.8 其他內容 ? 第2章 程序結構 ? 2.1 名稱 ? 2.2 聲明 ? 2.3 變量 ? 2.4 賦值 ? 2.5 類型聲明 ? 2.6 包和文件 ? 2.7 作用域 ? 第3章 基本數據 ? 3.1 整數 ? 3.2 浮點數 ? 3.3 復數? 3.4 布爾值 ? 3.5 字符串 ? 3.6 常量 ? 第4章 復合數據類型 ?61 4.1 數組 ?61 4.2 slice ?63 4.2.1 append函數 ?66 4.2.2 slice就地修改 ?69 4.3 map ?71 4.4 結構體 ?76 4.4.1 結構體字面量 ?78 4.4.2 結構體比較 ?80 4.4.3 結構體嵌套和匿名成員 ?80 4.5 JSON ?82 4.6 文本和HTML模板 ?87 第5章 函數 ?92 5.1 函數聲明 ?92 5.2 遞歸 ?93 5.3 多返回值 ?96 5.4 錯誤 ?98 5.4.1 錯誤處理策略 ?99 5.4.2 文件結束標識 ?101 5.5 函數變量 ?102 5.6 匿名函數 ?104 5.7 變長函數 ?110 5.8 延遲函數調用 ?111 5.9 宕機 ?115 5.10 恢復 ?118 第6章 方法 ?120 6.1 方法聲明 ?120 6.2 指針接收者的方法 ?122 6.3 通過結構體內嵌組成類型 ?124 6.4 方法變量與表達式 ?127 6.5 示例:位向量 ?128 6.6 封裝 ?130 第7章 接口 ?133 7.1 接口即約定 ?133 7.2 接口類型 ?135 7.3 實現接口 ?136 7.4 使用flag.Value來解析參數 ?139 7.5 接口值 ?141 7.6 使用sort.Interface來排序 ?144 7.7 http.Handler接口 ?148 7.8 error接口 ?152 7.9 示例:表達式求值器 ?154 7.10 類型斷言 ?160 7.11 使用類型斷言來識別錯誤 ?161 7.12 通過接口類型斷言來查詢特性 ?162 7.13 類型分支 ?164 7.14 示例:基于標記的XML解析 ?166 7.15 一些建議 ?168 第8章 goroutine和通道 ?170 8.1 goroutine ?170 8.2 示例:并發時鐘服務器 ?171 8.3 示例:并發回聲服務器 ?174 8.4 通道 ?176 8.4.1 無緩沖通道 ?177 8.4.2 管道 ?178 8.4.3 單向通道類型 ?180 8.4.4 緩沖通道 ?181 8.5 并行循環 ?183 8.6 示例:并發的Web爬蟲 ?187 8.7 使用select多路復用 ?190 8.8 示例:并發目錄遍歷 ?192 8.9 取消 ?195 8.10 示例:聊天服務器 ?198 第9章 使用共享變量實現并發 ?201 9.1 競態 ?201 9.2 互斥鎖:sync.Mutex ?205 9.3 讀寫互斥鎖:sync.RWMutex ?208 9.4 內存同步 ?208 9.5 延遲初始化:sync.Once ?210 9.6 競態檢測器 ?212 9.7 示例:并發非阻塞緩存 ?212 9.8 goroutine與線程 ?218 9.8.1 可增長的棧 ?219 9.8.2 goroutine調度 ?219 9.8.3 GOMAXPROCS ?219 9.8.4 goroutine沒有標識 ?220 第10章 包和go工具 ?221 10.1 引言 ?221 10.2 導入路徑 ?221 10.3 包的聲明 ?222 10.4 導入聲明 ?223 10.5 空導入 ?223 10.6 包及其命名 ?225 10.7 go工具 ?226 10.7.1 工作空間的組織 ?227 10.7.2 包的下載 ?228 10.7.3 包的構建 ?229 10.7.4 包的文檔化 ?231 10.7.5 內部包 ?232 10.7.6 包的查詢 ?233 第11章 測試 ?235 11.1 go test工具 ?235 11.2 Test函數 ?236 11.2.1 隨機測試 ?239 11.2.2 測試命令 ?240 11.2.3 白盒測試 ?242 11.2.4 外部測試包 ?245 11.2.5 編寫有效測試 ?246 11.2.6 避免脆弱的測試 ?247 11.3 覆蓋率 ?248 11.4 Benchmark函數 ?250 11.5 性能剖析 ?252 11.6 Example函數 ?254 第12章 反射 ?256 12.1 為什么使用反射 ?256 12.2 reflect.Type和reflect.Value ?257 12.3 Display:一個遞歸的值顯示器 ?259 12.4 示例:編碼S表達式 ?263 12.5 使用reflect.Value來設置值 ?266 12.6 示例:解碼S表達式 ?268 12.7 訪問結構體字段標簽 ?271 12.8 顯示類型的方法 ?273 12.9 注意事項 ?274 第13章 低級編程 ?276 13.1 unsafe.Sizeof、Alignof 和Offsetof ?276 13.2 unsafe.Pointer ?278 13.3 示例:深度相等 ?280 13.4 使用cgo調用C代碼 ?282 13.5 關于安全的注意事項 ?286
總結
以上是生活随笔為你收集整理的Go程序设计语言导读的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: go程序设计语言第十章-包管理和Go工具
- 下一篇: 【Go语言核心手册14】结语参考文献