適讀人群 :Go語言初學者以及中級水平的開發(fā)人員 Go語言正迅速成為構建Web服務的優(yōu)選語言。盡管市面上有大量的教程向具有其他編程語言經(jīng)驗的開發(fā)者講授Go語法,但要熟練掌握Go語言,這些教程遠遠不夠,它們并沒有介紹Go語言的慣例模式與編程實踐。本書將指導讀者學習編寫清晰且符合Go語言慣例的代碼所需的關鍵知識。
無論你的開發(fā)經(jīng)驗和水平如何,都將通過本書學會Go開發(fā)者的思考模式。作者Jon Bodner精心介紹了經(jīng)驗豐富的Go開發(fā)者所采用的設計模式,并說明了使用這些模式的理由。你還將提前了解Go即將發(fā)布的泛型特性,以及它是如何從設計到實現(xiàn),一步步融入Go語言的。
通過本書,你將:
學習如何在Go語言中編寫慣例代碼并設計Go項目。
理解Go語言設計中的權衡。
學會為獨立開發(fā)人員或團隊構建Go語言的開發(fā)環(huán)境。
了解如何以及何時使用反射、unsafe和cgo。
探究如何利用Go語言的特性使代碼高效運行。
了解哪些Go語言的特性應該少使用,或避免使用。
Go有小部分功能集與大多數(shù)其他現(xiàn)代編程語言格格不入。編寫良好的Go程序往往簡單明了,有時還有些重復。Go語言沒有繼承,沒有泛型(目前還沒有),沒有面向切面的編程(aspect-oriented programming),沒有函數(shù)重載,沒有操作符重載,沒有模式匹配,沒有命名參數(shù),沒有異常。讓很多人望而生畏的是,Go竟然有指針。Go的并發(fā)模型也與其他語言不同,但它基于20世紀70年代的思想,其垃圾收集器使用的算法也是如此。簡言之,Go有些復古,而這正是關鍵所在。
不過,無趣并不意味著平庸。要想正確使用Go,就需要了解它的功能是如何整合在一起的。即使你能夠?qū)懗隹雌饋硐馢ava或Python的Go代碼,也并不會滿足于得到的結果,并且想弄清楚所有這些特性背后的底層機制是怎么回事。這正是本書的意義所在。本書清楚地介紹了Go的特性,解釋了如何才能最大限度地使用它們來編寫可長期維護且符合Go語言慣例的代碼。
在需要構建某種可持續(xù)發(fā)展的事物時,無趣是件好事。如果一座橋是用一項未經(jīng)測試的技術建造而成的,即使工程師認為這項技術超級酷,也絕沒有人愿意成為第一個開車通過的人。許多編程語言在添加特性時并沒有考慮它們對代碼庫可維護性的影響。Go的目標正是讓開發(fā)者能夠更容易、更高效地在幾十年的軟件生命周期中持續(xù)構建規(guī);能浖。
Go語言確實很無趣,但是也很奇妙。希望本書能夠教會你如何用無趣的代碼構建令人振奮的項目。
【目標讀者】
本書的目標讀者是想要學習Go語言的開發(fā)者,尤其是Go語言的初學者。本書的重點不是簡單地用Go寫程序,而是寫出符合Go語言慣例的程序。有經(jīng)驗的Go開發(fā)者可以在書中找到關于如何最有效地使用該語言的新特性的建議。最重要的是,讀者希望能夠?qū)W到如何寫出像Go一樣的Go代碼。
讀者需要有開發(fā)者行業(yè)工具的使用經(jīng)驗,比如版本控制(最好是Git)和IDE。讀者還應該熟悉基本的計算機科學概念,如并發(fā)編程和抽象,因為書中解釋了它們?nèi)绾卧贕o中工作。其中一些代碼示例可以從GitHub上下載,還有幾十個示例可以在The Go Playground上在線試用。雖然互聯(lián)網(wǎng)連接不是必需的,但它在回顧可執(zhí)行示例時很有幫助。由于Go經(jīng)常被用來構建和調(diào)用HTTP服務端,所以有些示例需要讀者熟悉基本的HTTP概念。
雖然Go的大部分特性在其他語言中都能找到,但Go做出了不同的權衡,所以用它編寫的程序具有不同的結構。學習Go首先要從設置Go開發(fā)環(huán)境開始,然后涵蓋變量、類型、流程控制和功能。請不要跳過這些細節(jié),正是這些細節(jié)讓你的代碼符合Go的慣例。
【示例代碼】
可以從https://github.com/learning-go-book下載補充材料(示例代碼、練習、勘誤等)。
第1章 設置Go語言的開發(fā)環(huán)境7
1.1 安裝Go工具7
1.2 Go的工作空間8
1.3 Go命令集9
1.4 分析與審查13
1.5 選擇開發(fā)工具15
1.6 Makefile18
1.7 保持更新19
1.8 總結20
第2章 基礎類型和變量聲明21
2.1 內(nèi)置類型21
2.2 var與:= 30
2.3 const關鍵字32
2.4 有類型的常量與無類型的常量33
2.5 未使用的變量34
2.6 常量與變量的命名35
2.7 總結37
第3章 復合類型38
3.1 數(shù)組38
3.2 切片40
3.3 字符串、字符和字節(jié)49
3.4 映射52
3.5 結構體57
3.6 總結61
第4章 代碼塊、影子變量和流程控制62
4.1 代碼塊62
4.2 if語句66
4.3 for語句67
4.4 switch語句78
4.5 默認的switch語句81
4.6 if和switch之間的選擇82
4.7 goto語句83
4.8 總結85
第5章 函數(shù)86
5.1 函數(shù)的聲明和調(diào)用86
5.2 函數(shù)即值92
5.3 閉包95
5.4 defer98
5.5 函數(shù)的值調(diào)用101
5.6 總結103
第6章 指針104
6.1 指針快速入門104
6.2 不畏懼指針107
6.3 指針即可變的參數(shù)109
6.4 指針作為第二選擇113
6.5 指針傳遞可提高性能114
6.6 零值與無值114
6.7 映射與切片的區(qū)別115
6.8 切片用作緩沖區(qū)118
6.9 優(yōu)化垃圾回收119
6.10 總結121
第7章 類型、方法與接口122
7.1 Go語言的類型122
7.2 方法123
7.3 使用內(nèi)嵌進行組合131
7.4 內(nèi)嵌不是繼承132
7.5 接口概覽133
7.6 接口是類型安全的鴨子類型134
7.7 內(nèi)嵌與接口137
7.8 接收接口,返回結構體138
7.9 接口與nil139
7.10 空接口139
7.11 類型斷言與type-switch141
7.12 謹慎使用類型斷言與type-switch143
7.13 函數(shù)類型實現(xiàn)接口145
7.14 隱式接口實現(xiàn)依賴注入146
7.15 Wire150
7.16 Go并非傳統(tǒng)意義上的面向?qū)ο笳Z言150
7.17 總結150
第8章 錯誤151
8.1 如何處理錯誤151
8.2 使用字符串創(chuàng)建簡單錯誤152
8.3 哨兵錯誤153
8.4 錯誤是值155
8.5 包裝錯誤157
8.6 Is和As159
8.7 使用defer包裝錯誤162
8.8 panic和recover163
8.9 從錯誤中獲取堆棧跟蹤信息165
8.10 總結165
第9章 模塊、包和導入166
9.1 倉庫、模塊和包166
9.2 go.mod166
9.3 創(chuàng)建包167
9.4 模塊177
9.5 模塊的發(fā)布185
9.6模塊的版本控制186
9.7 模塊代理服務器187
9.8 總結188
第10章 Go的并發(fā)編程189
10.1 何時使用并發(fā)編程189
10.2 goroutine190
10.3 通道192
10.4 select語句194
10.5 并發(fā)實踐與模式197
10.6 何時使用互斥鎖211
10.7 atomic214
10.8 額外資源214
10.9 總結214
第11章 Go語言標準庫215
11.1 標準io庫215
11.2 time220
11.3 encoding/json222
11.4 net/http228
11.5 總結234
第12章 上下文235
12.1 什么是上下文235
12.2 取消238
12.3 計時器241
12.4 在上下文中處理取消請求243
12.5 傳遞值244
12.6 總結249
第13章 測試250
13.1 測試的基本知識250
13.2 表格驅(qū)動測試256
13.3 檢查代碼覆蓋率258
13.4 基準測試261
13.5 Go中的測試樁264
13.6 httptest269
13.7 集成測試和編譯標簽271
13.8 使用競爭檢測器檢查并發(fā)問題272
13.9總結274
第14章 惡龍禁區(qū):反射、unsafe和cgo275
14.1 在運行時使用反射處理類型275
14.2 unsafe意味著不安全289
14.3 cgo用于集成,而不是為了性能294
14.4 總結297
第15章 展望未來:Go中的泛型298
15.1 泛型減少冗余代碼,提高類型安全性298
15.2 Go中的泛型300
15.3 類型列表可指定操作符305
15.4 泛型函數(shù)抽象算法306
15.5 類型列表限制常量和實現(xiàn)307
15.6 暫不考慮的問題310
15.7 慣例模式與泛型312
15.8 未來更多可能312
15.9 總結313