100個 Go語言典型錯誤 100 Go Mistakes and How to Avoid Them

Go語言翻譯小組

買這商品的人也買了...

商品描述

Go語言"入門易,精通難”。想要用Go語言寫出優質的軟件,不僅要瞭解Go語言的語法,還需要對Go語言的特性、軟件的通用編寫方法、軟件項目的組織方法、並發程序設計、軟件測試、軟件性能優化等方面都有一定的瞭解。 本書既聚焦於Go語言,又不限於Go語言,介紹了開發者在使用Go語言時經常犯的100個經典錯誤,內容側重於語言核心和標準庫。對大多數錯誤的討論都提供了具體的示例,以說明在什麽時候容易犯這樣的錯誤。這不是一本教條主義的圖書,每個解決方案都詳細傳達了它應該適用的上下文。

目錄大綱

1 Go:入門易,精通難
1.1 Go 語言概述
1.2 簡單不意味著容易
1.3 100 個Go 語言錯誤
1.3.1 bug
1.3.2 不必要的復雜性
1.3.3 可讀性差
1.3.4 非最佳組織形式
1.3.5 API 對用戶不友好
1.3.6 代碼有待優化
1.3.7 效率低
總結
2 代碼和項目組織
2.1 #1:意想不到的變量隱藏
2.2 #2:不必要的嵌套代碼
2.3 #3:濫用init 函數
2.3.1 概念
2.3.2 何時使用init 函數
2.4 #4:過度使用getter 和setter
2.5 #5:避免接口污染
2.5.1 概念
2.5.2 何時使用接口
2.5.3 接口污染
2.6 #6:在生產者端的接口
2.7 #7:返回接口
2.8 #8:any 意味著nothing
2.9 #9:不知道什麽時候使用泛型
2.9.1 概念
2.9.2 常見的使用方法和誤用
2.10 #10:沒有意識到類型嵌入可能存在的問題
2.11 #11:不使用函數式選項模式
2.11.1 配置結構體
2.11.2 生成器模式
2.11.3 函數式選項模式
2.12 #12:項目組織混亂
2.12.1 項目結構
2.12.2 包組織
2.13 #13:創建實用程序包
2.14 #14:忽略包名稱沖突
2.15 #15:缺少代碼文檔
2.16 #16:不使用代碼檢查工具
總結
3 數據類型
3.1 #17:使用八進制字面量會帶來混淆
3.2 #18:容易忽視的整數溢出
3.2.1 概念
3.2.2 在遞增操作時檢測整數溢出
3.2.3 在加法操作中檢測整數溢出
3.2.4 在乘法操作中檢測整數溢出
3.3 #19:不瞭解浮點數
3.4 #20:不瞭解切片的長度和容量
3.5 #21:低效的切片初始化
3.6 #22:對 nil 和空切片的困惑 .
3.7 #23:未正確檢查切片是否為空
3.8 #24:無法正確復制切片
3.9 #25:使用append 的副作用
3.10 #26:切片和內存泄漏
3.10.1 容量泄漏
3.10.2 切片和指針
3.11 #27:低效的 map 初始化
3.11.1 概念
3.11.2 初始化
3.12 #28:map 和內存泄漏
3.13 #29:比較值時發生的錯誤
總結
4 控制結構
4.1 #30:忽視在 range 循環中元素被復制的事實
4.1.1 概念
4.1.2 值復制
4.2 #31:忽視 range 循環中參數是如何求值的
4.2.1 channel
4.2.2 數組
4.3 #32:忽視在 range 循環中使用指針元素的影響
4.4 #33:在 map 迭代過程中做出錯誤假設
4.4.1 排序
4.4.2 在迭代時往 map 中添加數據
4.5 #34:忽視break 語句是如何工作的
4.6 #35:在循環中使用defer
總結
5 字符串
5.1 #36:不理解 rune 的概念
5.2 #37:字符串迭代不準確
5.3 #38:亂用 trim 函數
5.4 #39:缺乏優化的字符串連接
5.5 #40:無用的字符串轉換
5.6 #41:子字符串和內存泄漏
總結
6 函數與方法
6.1 #42:不知道使用什麽類型的接收器
6.2 #43:不要使用命名的結果參數
6.3 #44:使用命名的結果參數的意外副作用
6.4 #45:返回一個 nil 接收器
6.5 #46:使用文件名作為函數輸入
6.6 #47:忽略defer 語句參數和接收器的計算
6.6.1 參數計算
6.6.2 指針和值接收器
總結
7 錯誤管理
7.1 #48:panic
7.2 #49:搞不清何時需要包裝錯誤
7.3 #50:不準確的錯誤類型檢查
7.4 #51:錯誤地檢查錯誤值
7.5 #52:處理同一個錯誤兩次
7.6 #53:忽略錯誤
7.7 #54:忽略 defer 語句返回的錯誤
總結
8 並發:基礎
8.1 #55:混淆並發和並行
8.2 #56:認為並發總是更快
8.2.1 Go 調度
8.2.2 並行歸並排序
8.3 #57:對何時使用channel 或互斥鎖感到困惑
8.4 #58:不理解競爭問題
8.4.1 數據競爭與競爭條件
8.4.2 Go 內存模型
8.5 #59:不瞭解工作負載類型對並發的影響
8.6 #60:誤解 Go 上下文
8.6.1 最後期限
8.6.2 取消信號
8.6.3 上下文值
8.6.4 感知上下文的取消信號
總結
9 並發:實踐
9.1 #61:傳播不恰當的上下文
9.2 #62:在不知道何時停止的情況下啟動 goroutine
9.3 #63:沒有小心處理 goroutine 和循環變量
9.4 #64:使用 select 和channel 來期待確定性行為
9.5 #65:沒有使用通知channel
9.6 #66:沒有使用 nil channel
9.7 #67:對channel 緩沖區大小感到困惑
9.8 #68:忘記字符串格式化可能產生的副作用
9.8.1 etcd 數據競爭
9.8.2 死鎖
9.9 #69:使用 append 函數創造了數據競爭
9.10 #70:對切片和 map 不準確地使用互斥鎖
9.11 #71:錯誤使用 sync.WaitGroup
9.12 #72:忘記了 sync.Cond
9.13 #73:沒有使用 errgroup
9.14 #74:復制sync 類型
總結
10 標準庫
10.1 #75:提供錯誤的持續時間
10.2 #76:time.After 和內存泄漏
10.3 #77:常見的JSON 處理錯誤
10.3.1 由嵌入式字段導致的非預期行為
10.3.2 JSON 和單調時鐘
10.3.3 map 中的any 類型
10.4 #78:常見的 SQL 錯誤
10.4.1 忘記sql.Open 不一定與數據庫建立連接
10.4.2 忘記連接池導致的問題
10.4.3 未使用預準備的語句
10.4.4 對空值處理不當
10.4.5 沒有處理行迭代錯誤
10.5 #79:沒有關閉瞬時資源
10.5.1 HTTP Body
10.5.2 sql.Rows
10.5.3 os.File
10.6 #80:在響應HTTP 請求後忘記加return 語句
10.7 #81:使用默認的HTTP 客戶端和服務端
10.7.1 HTTP 客戶端
10.7.2 HTTP 服務端
總結
11 測試
11.1 #82:未區分測試種類
11.1.1 build 標識
11.1.2 環境變量
11.1.3 短模式
11.2 #83:未打開-race 開關
11.3 #84:未使用測試執行模式
11.3.1 parallel 標識
11.3.2 shuffle 標識
11.4 #85:未使用表格驅動型測試
11.5 #86:在單元測試中休眠
11.6 #87:沒有有效處理 time API
11.7 #88:未使用測試工具包
11.7.1 httptest 包
11.7.2 iotest 包
11.8 #89:寫出不準確的基準測試
11.8.1 未重置或暫停計時器
11.8.2 對微基準測試做出錯誤假設
11.8.3 未註意編譯器優化
11.8.4 被觀察者效應愚弄
11.9 #90:未探索所有的 Go 測試特性
11.9.1 代碼覆蓋率
11.9.2 從一個不同的包進行測試
11.9.3 工具函數
11.9.4 設置和拆卸
總結
12 優化
12.1 #91:不瞭解 CPU 緩存
12.1.1 CPU 架構
12.1.2 緩存行
12.1.3 包含結構體的切片 vs 包含切片的結構體
12.1.4 可預測性
12.1.5 緩存放置策略
12.2 #92:編寫導致偽共享的並發代碼
12.3 #93:不考慮指令級並行性
12.4 #94:不瞭解數據對齊
12.5 #95:不瞭解棧與堆
12.5.1 棧 vs 堆
12.5.2 逃逸分析
12.6 #96:不瞭解如何減少分配
12.6.1 修改 API
12.6.2 編譯器優化
12.6.3 sync.Pool
12.7 #97:沒有依賴內聯
12.8 #98:沒有使用Go 診斷工具
12.8.1 分析工具
12.8.2 跟蹤工具
12.9 #99:不瞭解 GC 的工作原理
12.9.1 概念
12.9.2 示例
12.10 #100:不瞭解在 Docker 和 Kubernetes 中運行Go 程序的影響
總結
結語