深入淺出Go語言編程從原理解析到實戰進階
阮正平
買這商品的人也買了...
-
$650$507 -
$880$695 -
$1,000$780 -
$560$437 -
$500$390 -
$720$562 -
$648$616 -
$550$429 -
$588$559 -
$680$530 -
$539$512 -
$564深入理解 Go 語言
-
$768$730 -
$556搞定系統設計:面試敲開大廠的門
-
$454高效使用 Redis:一書學透數據存儲與高可用集群
-
$551RTC程序設計:實時音視頻權威指南
-
$551TypeScript + React Web 應用開發實戰
-
$539$512 -
$299$284 -
$534$507 -
$390$371 -
$588$559 -
$880$695 -
$352Linux 企業運維實戰 (Redis + Zabbix + Nginx + Prometheus + Grafana + LNMP)
-
$850$638
相關主題
商品描述
本書是一部從核心概念、設計原理、應用場景、操作方法和實戰技巧等維度全面、深入探討 Go 語言的著
作。書中首先介紹 Go 語言的基本概念,並通過“hello world”程序引導讀者熟悉 Go 的工具鏈。接下來逐步深
入,介紹面向包的設計、測試框架、錯誤與異常處理等內容。第 8 章開始探討指針和內存逃逸分析,這對於理
解 Go 語言的內存模型至關重要。隨後的章節涉及數據結構、面向對象和接口編程等核心知識。從第 15 章開始,
重點轉向並發編程,從基本的並發模式到復雜的並發原理,再到內存管理和垃圾回收等高級主題。最後幾
章關註實際開發中的問題,如使用標準庫和第三方庫、性能問題分析與追蹤,以及重構“hello world”示
例代碼。
本書適合想要掌握 Go 語言的基本使用方法,以及瞭解其底層工作原理和設計實現的初、中級讀者閱讀。
作者簡介
阮正平,高级工程师,拥有十多年软件开发设计经验。擅长Golang、Docker、Kubernetes、数据库等技术,主要研究方向为云原生、数据库、区块链。目前任某公司架构师,负责公司的Serverless PaaS平台设计和开发,助力企业从传统应用迁移至云原生应用。
杜军,浙大SEL实验室硕士,国内早期的一批容器技术布道师。对云计算技术演进与内在驱动力有深刻见解,主要研究方向为容器、微服务、DevOps、边缘计算。
目錄大綱
第 1 章 Go 語言初探 1
1.1 Go 語言的發展里程碑 1
1.2 雲時代 Go 語言的發展趨勢 2
1.3 Go 語言優秀的語言特性 3
1.3.1 “少即是多”的設計哲學 3
1.3.2 強大的 runtime 4
1.3.3 面向接口編程 5
1.3.4 為工程服務的語言 6
1.3.5 自帶標準化的測試框架 7
1.3.6 豐富的標準庫和第三方庫 7
1.4 強大的生態圈和成功案例 8
1.5 Go 程序是如何運行的 8
1.6 plan9 與 Go 語言 10
1.6.1 寄存器 10
1.6.2 Go 語言的反匯編方法 11
1.6.3 反匯編的查看示例 13
第 2 章 “hello world”與工具鏈 15
2.1 Go 語言的安裝和配置 15
2.1.1 下載和安裝 15
2.1.2 配置 Go 語言的環境變量 15
2.1.3 查看配置信息 16
2.2 第 一個程序“hello world” 16
2.2.1 “hello world”程序的代碼說明 17
2.2.2 代碼的編譯與運行 21
2.2.3 “hello world”示例總結 21
2.3 Go 語言的工具鏈命令 22
2.3.1 與編譯執行有關的工具鏈命令 22
2.3.2 獲取與安裝第三方包 22
2.3.3 工具包組合命令 go tool 23
2.3.4 跨平臺交叉編譯 23
2.3.5 網絡代理 GOPROXY 24
第 3 章 Go 語言的基礎知識 26
3.1 Go 語言的常用規範 26
3.1.1 命名與註釋 26
3.1.2 聲明 27
3.1.3 對變量賦值 28
3.1.4 包和文件 28
3.2 數據類型 29
3.2.1 基本類型 29
3.2.2 非引用類型和引用類型 31
3.2.3 用戶自定義類型 32
3.2.4 類型別名 32
3.2.5 傳參方式 33
3.3 變量的本質 33
3.3.1 類型的兩個要素 33
3.3.2 變量的聲明 34
3.3.3 零值機制 35
3.3.4 短變量聲明與類型轉換 35
3.4 常量 36
3.4.1 常量 iota 37
3.4.2 常量的類型提升機制 38
3.5 運算符 38
3.5.1 算術運算符 39
3.5.2 比較運算符 39
3.5.3 邏輯運算符 39
3.5.4 位運算符 40
3.5.5 賦值運算符 40
3.5.6 指針運算符 41
3.6 結構化語法 41
3.6.1 循環結構 41
3.6.2 條件語句 42
3.6.3 switch-case 語句 42
3.6.4 控制或跳出循環語句的關鍵字 43
3.7 類型轉換 43
3.7.1 轉換的語法 44
3.7.2 類型斷言 44
3.8 Go 語言的語法糖 44
3.8.1 短變量聲明和new 函數 44
3.8.2 符號“”與切片 44
3.8.3 for range 45
第 4 章 面向包的設計與依賴管理 46
4.1 包的使用 46
4.1.1 包的概述 46
4.1.2 包的查找方式 47
4.1.3 包加載的順序 48
4.1.4 包中 init 函數的加載 49
4.1.5 包加載順序的示例 49
4.1.6 包的使用總結 50
4.2 面向包的設計 50
4.3 包管理工具 Go Module 51
4.3.1 包管理的方式 51
4.3.2 Go Module 簡介 52
4.3.3 開啟 Go Module 52
4.3.4 Go Module 的優點 52
4.3.5 使用 Go Module 53
4.3.6 go.mod 文件中的命令 57
4.3.7 升級依賴包的方法 58
4.3.8 依賴包版本的選擇 58
4.3.9 語義版本的導入路徑語法 58
4.3.10 Go Module 的使用總結 59
第 5 章 測試框架 60
5.1 Go 語言中的測試框架 60
5.1.1 測試使用的約定 60
5.1.2 標準庫 testing 的輔助功能函數 61
5.1.3 測試框架示例 61
5.1.4 使用測試命令 62
5.2 單元測試 63
5.2.1 指定測試用例 63
5.2.2 單元測試之子測試 64
5.2.3 幫助函數 64
5.3 測試代碼的覆蓋率 65
5.4 斷言 66
5.5 基準測試 67
5.5.1 基準測試場景 67
5.5.2 基準測試的方法 67
5.5.3 基準測試之子測試 68
5.5.4 基準測試示例 68
5.6 與網絡有關的模擬測試 70
5.7 與測試有關的第三方工具 71
5.7.1 gomock 71
5.7.2 BDD 71
第 6 章 錯誤與異常處理 73
6.1 error 的引入 73
6.1.1 預定義的錯誤類型 74
6.1.2 快速創建錯誤類型 74
6.1.3 自定義錯誤 75
6.1.4 接口在錯誤處理上的妙用 76
6.1.5 自定義錯誤的陷阱 77
6.1.6 獲取和處理錯誤 78
6.1.7 Go 語言作者關於錯誤處理的觀點 78
6.2 異常處理 79
6.2.1 panic 的使用 79
6.2.2 defer 函數的設計與使用陷阱 79
6.2.3 recover 函數的使用 81
6.3 面向錯誤和恢復的設計 82
6.4 帶堆棧信息的 error 83
6.5 標準庫 errors 的改進 84
6.6 errGroup 對象 86
6.7 日誌系統的引入 87
6.7.1 日誌概述 88
6.7.2 第三方日誌框架 88
第 7 章 編碼與字符串 89
7.1 字符編碼 89
7.1.1 字符的編碼方式 89
7.1.2 使用字符類型的註意事項 90
7.2 字符串 90
7.2.1 字符串的聲明和初始化 90
7.2.2 字符串的數據結構 90
7.2.3 遍歷字符串 91
7.2.4 字符串的長度問題 92
7.2.5 字符串的備份 92
7.2.6 字符串拼接 92
7.3 字符串與基本類型互轉 94
第 8 章 指針與內存逃逸分析 96
8.1 活動幀的作用 96
8.2 值語義的本質 98
8.3 指針 99
8.3.1 指針的由來 99
8.3.2 指針和指針類型 100
8.3.3 使用指針運算符的註意事項 101
8.3.4 nil 指針 101
8.3.5 指針數組與數組指針 102
8.3.6 關於指針的補充說明 102
8.4 內存逃逸分析 103
8.4.1 內存逃逸分析的由來 103
8.4.2 內存逃逸分析的作用 103
8.4.3 兩種情況會引起內存逃逸分析 103
8.4.4 內存逃逸分析示例 104
8.4.5 函數內聯 106
8.4.6 手動控制內存逃逸分析 107
8.5 引用類型與深、淺拷貝 108
第 9 章 數據結構 109
9.1 面向數據的設計 109
9.1.1 編碼和硬件 109
9.1.2 可預測的內存訪問模式 111
9.2 數組 111
9.2.1 數組的聲明及初始化 112
9.2.2 數組在內存中的形式 112
9.2.3 遍歷數組 113
9.2.4 數組的截取 113
9.2.5 數組的反轉 114
9.3 切片 114
9.3.1 切片的設計 114
9.3.2 切片的創建與初始化 116
9.3.3 切片的長度與容量 117
9.3.4 nil 切片和空切片 117
9.3.5 切片的共享底層數組 118
9.3.6 append 函數與切片的擴容 119
9.3.7 append 函數引發的內存泄漏 121
9.3.8 三下標切片 122
9.3.9 切片的復制 122
9.3.10 切片的比較 122
9.3.11 刪除切片中的元素 123
9.3.12 特殊的切片:字符串 125
9.3.13 數組與切片的對比 125
9.4 映射 125
9.4.1 選擇合適的鍵值類型 126
9.4.2 映射的聲明和初始化 127
9.4.3 映射的使用 128
9.4.4 映射的排序 129
9.4.5 映射的擴容 130
9.4.6 映射的並發安全性 130
9.4.7 映射的刪除機制 132
9.4.8 映射的設計 133
9.5 數據結構中的常見問題 138
9.5.1 make 與 new 的差異 138
9.5.2 使用引用類型前先分配空間 139
9.5.3 可能發生內存泄漏的情況 139
第 10 章 結構體與內存對齊 140
10.1 結構體 140
10.1.1 結構體的定義 140
10.1.2 結構體的初始化 142
10.1.3 結構體的類型轉換 143
10.1.4 結構體比較 143
10.1.5 結構體的值 144
10.2 序列化與反序列化 145
10.2.1 序列化 145
10.2.2 反序列化 145
10.2.3 使用 tag 146
10.3 unsafe 包 147
10.3.1 unsafe.Pointer 類型 147
10.3.2 unsafe 包簡介 147
10.3.3 unsafe 包中的函數 148
10.3.4 unsafe 包的使用方式 150
10.4 內存對齊 152
10.4.1 內存對齊的概念 152
10.4.2 數據類型的尺寸 153
10.4.3 內存自動對齊 153
10.4.4 內存對齊的示例 154
第 11 章 函數 155
11.1 認識函數 155
11.1.1 函數的定義 155
11.1.2 函數的種類 156
11.2 defer 函數 158
11.2.1 defer 函數的使用場景 158
11.2.2 當 panic 遇到defer 函數 159
11.2.3 defer 函數與for 循環語句 160
11.3 作為數據類型的函數 161
11.4 函數類型的使用場景 161
11.4.1 匿名函數 161
11.4.2 回調函數 162
11.4.3 閉包 163
11.5 函數的別名 165
第 12 章 面向“對象”編程 166
12.1 封裝 166
12.1.1 方法 166
12.1.2 方法的聲明方式 167
12.1.3 接收者類型與接收者基礎類型 167
12.1.4 接收者使用的語義 168
12.1.5 兩種語義本質上的區別 169
12.1.6 解耦帶來的問題 170
12.1.7 更為復雜的調用方式 170
12.1.8 隱式轉換 171
12.1.9 關於封裝的總結 173
12.2 繼承 173
12.2.1 Go 語言不支持繼承 173
12.2.2 用“內嵌+組合”替代繼承 174
12.2.3 擴展已有的包 175
12.3 多態 176
12.3.1 接口的定義 176
12.3.2 鴨子類型 176
12.3.3 接口與協議 178
12.3.4 接口如何實現多態 178
第 13 章 面向接口編程 180
13.1 接口編程哲學 180
13.2 接口與組合 181
13.2.1 接口的設計準則 181
13.2.2 接口與組合示例 182
13.2.3 組合的多樣化 183
13.3 接口的剖析 183
13.3.1 與接口相關的說明 183
13.3.2 空接口與包裹 184
13.3.3 實現接口類型 185
13.3.4 接口包裹非接口值 185
13.3.5 接口與多態 185
13.3.6 接口類型斷言 186
13.3.7 強制轉換接口類型 187
13.3.8 接口類型與隱式聲明 187
13.3.9 類型轉換的時間復雜度 188
13.4 接口的設計原則 188
13.4.1 錯誤的接口設計 189
13.4.2 基於數據驅動的接口設計 189
13.4.3 類型斷言在 API 設計中的應用 189
13.4.4 接口設計的建議 190
13.5 檢查接口的實現 190
13.6 空接口與類型斷言 193
13.7 接口值的比較 194
13.8 檢查運行階段的接口類型 195
第 14 章 反射 196
14.1 反射的概念 196
14.2 接口與反射 198
14.2.1 靜態類型與動態類型 198
14.2.2 空接口 199
14.2.3 類型的底層分析 199
14.3 反射包介紹 201
14.3.1 理解反射對象的轉換機制 201
14.3.2 reflect.Type 接口的轉換方式 202
14.3.3 reflect.Value 結構體類型的使用方法 204
14.4 反射包的使用示例 207
14.4.1 獲取變量的類型和值 208
14.4.2 獲取結構體的屬性和方法 209
14.4.3 動態調用方法和傳值 209
14.4.4 修改接口值 210
14.4.5 判斷結構體實現了哪個接口 211
14.5 反射的三個定律 212
14.6 反射的應用場景 212
14.7 反射的性能 213
第 15 章 並發編程 214
15.1 感受並發的魅力 214
15.1.1 並發和並行 214
15.1.2 並發帶來的好處 215
15.1.3 “hello goroutine” 215
15.1.4 協程的執行順序 216
15.1.5 控制協程的幾種方式 216
15.2 sync.WaitGroup 217
15.2.1 sync.WaitGroup 的三個方法 217
15.2.2 使用 sync.WaitGroup 的模板 217
15.2.3 使用 sync.WaitGroup 時的註意事項 218
15.2.4 為 sync.WaitGroup 增加額外的功能 218
15.3 數據競爭問題 219
15.3.1 臨界區 219
15.3.2 數據競爭的檢測方法 219
15.3.3 解決臨界區的數據安全問題 220
15.4 傳統的鎖 221
15.4.1 鎖的概念 221
15.4.2 互斥鎖 Mutex 222
15.4.3 Mutex 的工作模式 224
15.4.4 讀寫鎖 RWMutex 224
15.4.5 重入與 TryLock 226
15.5 原子操作介紹 227
15.5.1 Go 語言中的原子操作 228
15.5.2 atomic 包的使用 228
第 16 章 並發與通道 230
16.1 通道的行為 230
16.2 創建通道 231
16.3 通道的特性 231
16.3.1 通道的成對性 231
16.3.2 通道的阻塞性 232
16.3.3 通道與死鎖 232
16.3.4 讓出當前協程的執行權 233
16.3.5 關閉通道 234
16.3.6 遍歷通道 236
16.4 通道的其他特性 237
16.4.1 帶緩沖的通道 237
16.4.2 緩沖區與延遲保障 238
16.4.3 通道的方向 239
16.4.4 通道的狀態 239
16.5 通道的使用建議 239
16.6 select 機制 240
16.6.1 select 機制的介紹與示例 241
16.6.2 select 與超時控制 242
16.7 通道的模式 243
16.7.1 等待任務模式 243
16.7.2 等待結果模式 244
16.7.3 等待完成模式 246
16.7.4 Pooling 模式 247
16.7.5 流水線模式 248
16.7.6 FanOut/FanIn 模式 249
16.7.7 Drop 模式 251
第 17 章 其他並發技術 252
17.1 context 包 252
17.1.1 context 包的使用場景 253
17.1.2 context 包中的接口和函數 253
17.1.3 context 包的使用流程 254
17.1.4 context.Context 接口 255
17.1.5 生成 Context 的方法 255
17.1.6 Context 與請求超時 258
17.1.7 Context 的使用總結 260
17.2 sync.Cond 261
17.3 sync.Once 262
17.4 sync.Map 263
17.5 sync.Pool 265
17.5.1 sync.Pool 的介紹 265
17.5.2 緩存對象的生命周期 266
17.5.3 sync.Pool 的使用場景及存在的問題 267
17.6 實現對象池 268
17.7 常用連接池 269
17.8 並發技術選型 270
第 18 章 並發原理 271
18.1 怎樣讓程序跑得更快 271
18.1.1 從單進程到多線程 271
18.1.2 工作任務的種類 272
18.2 Go 語言中的協程 273
18.2.1 內核態線程與用戶態線程 273
18.2.2 輕量級的協程 274
18.2.3 改造後的 Go 語言協程 275
18.2.4 簡說 Go 語言協程的調度 275
18.2.5 協作式與搶占式調度器 277
18.2.6 協程與 I/O 多路復用 277
18.3 GPM 調度流程 278
18.3.1 GPM 調度模型 278
18.3.2 G 的調度 280
18.3.3 P 的調度 282
18.3.4 M 的調度 285
18.3.5 探索調度器的調度流程 286
18.3.6 循環調度 290
18.3.7 任務執行函數 execute 294
18.4 監控線程 sysmon 297
18.5 main 函數與協程的執行順序 299
18.6 可視化分析 GPM 調度 300
18.6.1 使用 trace 分析GPM 調度 300
18.6.2 使用 GODEBUG調試 GPM 調度 302
18.7 深入探索通道 303
18.7.1 通道的底層數據結構hchan 303
18.7.2 發生阻塞的條件 304
18.7.3 select 多路復用的底層邏輯 305
第 19 章 內存管理 307
19.1 runtime 307
19.2 內存分配模型 307
19.2.1 內存模型 308
19.2.2 內存分配過程 308
19.2.3 span 與默認的內存大小和規格 309
19.3 內存管理單元 310
19.3.1 mspan 311
19.3.2 mheap 312
19.3.3 heapArena 313
19.3.4 mcentral 313
19.3.5 mcache 315
19.3.6 內存的多級分配管理 316
19.4 對象分類及分配策略 317
19.4.1 微小對象 317
19.4.2 小對象和大對象 318
19.5 堆內存分配總結 318
第 20 章 垃圾回收 319
20.1 垃圾回收算法 320
20.2 Go 語言的垃圾回收算法 321
20.2.1 標記清掃算法 322
20.2.2 三色標記法 323
20.2.3 三色標記與並發問題 325
20.2.4 三色不變式與屏障技術 326
20.2.5 插入寫屏障 327
20.2.6 刪除寫屏障 330
20.2.7 混合寫屏障 333
20.2.8 並發增量式垃圾回收 334
20.3 觸發垃圾回收的時機 334
20.4 查看運行時的垃圾回收信息 335
20.5 垃圾回收優化示例 337
20.5.1 傳遞復雜對象時建議使用指針 337
20.5.2 自動擴容的代價 339
第 21 章 使用標準庫和第三方庫 341
21.1 I/O 操作 342
21.1.1 io 包 342
21.1.2 os 包 343
21.1.3 bufio 包 344
21.1.4 bytes 包 345
21.1.5 ioutil 包與替換方案 346
21.1.6 讀取文件的示例 346
21.1.7 大文件讀取方案 348
21.1.8 文件的復制 350
21.1.9 斷點續傳 351
21.2 網絡操作 352
21.2.1 Socket 編程 352
21.2.2 net/http 包 355
21.2.3 與網絡編程相關的其他包 359
21.3 與時間有關的標準庫 359
21.3.1 時間函數 360
21.3.2 時間戳 360
21.3.3 時間的格式化與解析 361
21.4 隨機數 362
21.5 正則表達式 362
21.6 flag 包的使用 363
21.6.1 簡單標記的聲明方式 363
21.6.2 其他使用方式 364
21.7 os 包的使用 365
21.8 crypto 包 367
21.9 base64 編碼 367
21.10 fmt 包 368
21.11 使用第三方庫 369
第 22 章 性能問題分析與追蹤 370
22.1 性能優化概述 370
22.2 性能優化的步驟 371
22.3 硬件與軟件的性能指標 373
22.4 優化工具概述 374
22.4.1 runtime.MemStats 374
22.4.2 Benchmark 374
22.4.3 go tool pprof 工具 375
22.4.4 runtime/pprof 包 375
22.4.5 net/http/pprof 包 376
22.4.6 go tool trace 工具 377
22.4.7 fgprof 包 377
22.4.8 coredump 377
22.4.9 gcflags 379
22.4.10 GODEBUG 379
22.4.11 使用場景總結 380
22.5 性能優化總結 380
22.6 使用 go tool pprof 工具進行性能分析的示例 380
22.7 pprof 包結合 HTTP 服務使用的示例 387
22.8 pprof 包和 fgprof 包的使用對比 390
22.9 go tool trace 工具的使用示例 391
22.10 持續性能分析 392
22.11 性能問題的定位及處理建議 393
22.11.1 CPU 占用率高的定位及處理建議 393
22.11.2 內存使用率高的定位及處理建議 394
22.11.3 I/O 高的定位及處理建議 395
22.11.4 阻塞問題的定位及處理建議 395
22.11.5 協程泄露的定位及處理建議 396
第 23 章 重構“hello world” 397
23.1 搭建業務處理框架 397
23.2 設計解耦的讀寫接口 398
23.2.1 用結構體代替讀寫方法 398
23.2.2 使用組合接口 399
23.3 業務實現 401
23.3.1 讀日誌數據 401
23.3.2 Nginx 日誌數據的說明及處理 402
23.3.3 處理日誌數據的關鍵代碼 403
23.3.4 實現數據歸檔 404
23.4 構建 HTTP 服務發布數據 405
23.4.1 埋點處理 405
23.4.2 構建 HTTP 服務發布數據的步驟 406
23.5 整合 Prometheus 發布數據 408
23.5.1 引用第三方prometheus 包 408
23.5.2 實現自定義的exporter 409
23.6 代碼細節的提升 412
23.7 總結 412