Go的編程習慣

  1. Go語言的習慣是在if中處理錯誤然後直接返回,這樣可以確保正常執行的語句不需要代碼縮進。在Go中,錯誤處理有一套獨特的編碼風格。檢查某個子函數是否失敗後,我們通常將處理失敗的邏輯代碼放在處理成功的代碼之前。如果某個錯誤會導致函數返回,那麼成功時的邏輯代碼不應放在else語句塊中,而應直接放在函數體中。Go中大部分函數的代碼結構幾乎相同,首先是一系列的初始檢查,防止錯誤發生,之後是函數的實際邏輯。
  2. 儘管Go語言提供了無符號數和運算,即使數值本身不可能出現負數我們還是傾向於使用有符號的int類型,就像數組的長度那樣,雖然使用uint無符號類型似乎是一個更合理的選擇。事實上,內置的len函數返回一個有符號的int。(主要是避免在自減的時候和0比較出現錯誤,無符號的數永遠都會大於0)無符號數往往只有在位運算或其它特殊的運算場景纔會使用,就像bit集合、分析二進制文件格式或者是哈希和加密操作等。它們通常並不用於僅僅是表達非負數量的場合。 
  3. 如果一個函數返回的浮點數結果可能失敗,最好的做法是用單獨的標誌報告失敗,像這樣:
    func compute() (value float64, ok bool) {
    // ...
    if failed {
    return 0, false
    } r
    eturn result, true
    } 

  4. 向bytes.Buffer添加任意字符的UTF8編碼時,最好使用bytes.Buffer的WriteRune方法,但是WriteByte方法對於寫入類似'['和']'等ASCII字符則會更加有效。

  5. 在開始寫一個新程序之前,最好先去檢查一下是不是已經有了現成的庫可以幫助你更高效地完成這件事情。你可以在 https://golang.org/pkg 和 https://godoc.org 中找到標準庫和社區寫的packagegodoc這個工具可以讓你直接在本地命令行閱讀標準庫的文檔。 

  6. 通常,包註釋的第一句應該先是包的功能概要說明。一個包通常只有一個源文件有包註釋(譯註:如果有多個包註釋,目前的文檔工具會根據源文件名的先後順序將它們鏈接爲一個包註釋) 。如果包註釋很大,通常會放到一個獨立的doc.go文件中。

  7. Unicode字符rune類型是和int32等價的類型,通常用於表示一個Unicode碼點。這兩個名稱可以互換使用。同樣byte也是uint8類型的等價類型,byte類型一般用於強調數值是一個原始的數據而不是一個小的整數。 

  8. 儘管Go語言提供了無符號數和運算,即使數值本身不可能出現負數我們還是傾向於使用有符號的int類型,就像數組的長度那樣,雖然使用uint無符號類型似乎是一個更合理的選擇(這樣無需考慮和0作比較應考慮的問題)。事實上,內置的len函數返回一個有符號的int 。

  9. 我們應該在每次函數調用後,都養成考慮錯誤處理的習慣,當你決定忽略某個錯誤時,你應該在清晰的記錄下你的意圖。

  10. 當某些不應該發生的場景發生時,我們就應該調用panic。 

  11. 斷言函數必須滿足的前置條件是明智的做法,但這很容易被濫用。除非你能提供更多的錯誤信息,或者能更快速的發現錯誤,否則不需要使用斷言,編譯器在運行時會幫你檢查代碼。 

  12. 在健壯的程序中,任何可以預料到的錯誤,如不正確的輸入、錯誤的配置或是失敗的I/O操作都應該被優雅的處理,最好的處理方式,就是使用Go的
    錯誤機制。 

  13. 不加區分的恢復所有的panic異常,不是可取的做法;因爲在panic之後,無法保證包級變量的狀態仍然和我們預期一致。比如,對數據結構的一次重要更新沒有被完整完成、文件或者網絡連接沒有被關閉、獲得的鎖沒有被釋放。此外,如果寫日誌時產生的panic被不加區分的恢復,可能會導致漏洞被忽略。
    雖然把對panic的處理都集中在一個包下,有助於簡化對複雜和不可以預料問題的處理,但作爲被廣泛遵守的規範,你不應該試圖去恢復其他包引起的panic。公有的API應該將函數的運行失敗作爲error返回,而不是panic。同樣的,你也不應該恢復一個由他人開發的函數引起的panic,比如說調用者傳入的回調函數,因爲你無法確保這樣做是安全的。
    基於以上原因,安全的做法是有選擇性的recover。換句話說,只恢復應該被恢復的panic異常,此外,這些異常所佔的比例應該儘可能的低。爲了標識某個panic是否應該被恢復,我們可以將panic value設置成特殊類型。在recover時對panic value進行檢查,如果發現panic value是特殊類型,就將這個panic作爲errror處理,如果不是,則按照正常的panic進行處理。

  14. 我們可以任意的選擇接收器的名字。由於接收器的名字經常會被使用到,所以保持其在方法間傳遞時的一致性和簡短性是不錯的主意。這裏的建議是可以使用其類型的第一個字母。

  15. 當定義一個允許nil作爲接收器值的方法的類型時,在類型前面的註釋中指出nil變量代表的意義是很有必要的,就像我們上面例子裏做的這樣。 

  16. 只用來訪問或修改內部變量的函數被稱爲setter或者getter,例子如下,比如log包裏的Logger類型對應的一些函數。在命名一個getter方法時,我們通常會省略掉前面的Get前綴。這種簡潔上的偏好也可以推廣到各種類型的前綴比如Fetch,Find或者Lookup。

  17. 慣例來說,被mutex所保護的變量是在mutex變量聲明之後立刻聲明的。如果你的做法和慣例不符,確保在文檔裏對你的做法進行說明。

  18. 所有併發的問題都可以用一致的、簡單的既定的模式來規避。所以可能的話,將變量限定在goroutine內部;如果是多個goroutine都需要訪問的變量,使用互斥條件來訪問。 

  19. Go語言的編碼風格鼓勵爲每個包提供良好的文檔。包中每個導出的成員和包聲明前都應該包含目的和用法說明的註釋。

     

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章