Go代碼規范(Code Review)
總結幾個開發程序中經常會犯的代碼規范錯誤
參考鏈接:https://learnku.com/go/wikis/48375
注釋陳述句
// Request 表示運行命令的請求,
type Request struct { ...
// Encode 將 req 的 JSON 編碼寫入 w ,
func Encode(w io.Writer, req *Request) { ...
背景關系
大部分使用背景關系的函式都要將其作為第一個引數
func F(ctx context.Context, /* 其他引數 */) {}
不建議把背景關系作為成員添加到結構型別中
// 不建議寫法
type MyContext struct {
ctx context.Context
}
Crypto Rand
不要使用 math/rand 來生成密鑰,即使是一次性密鑰,在沒有種子(seed)的情況下,生成器是完全可以被預測的,請使用 crypto/rand 的 Reader 作為替代
func Key() string {
buf := make([]byte, 16)
_, err := rand.Read(buf)
if err != nil {
panic(err) // 出于隨機性,永遠都不會發生
}
return fmt.Sprintf("%x", buf)
// or hex.EncodeToString(buf)
// or base64.StdEncoding.EncodeToString(buf)
}
func main() {
fmt.Println(Key())
}
//輸出
//4799b801e7866209593cfaedb03cf8da
宣告空的切片
當宣告一個空 slice 時,傾向于用
var t []string
而不是
t := []string{}
前者宣告了一個 nil slice 值,而后者宣告了一個非 nil 但是零長度的 slice,兩者在功能上等同,len 和 cap 均為零,而 nil slice 是首選的風格,
請注意,在部分場景下,首選非 nil 但零長度的切片,例如編碼 JSON 物件時(nil 切片編碼為 null,而則 []string{} 可以正確編碼為 JSON array []),
包注釋
/*
Package template implements data-driven templates for generating textual
output such as HTML.
....
*/
package template
如果包很簡單,包注釋可以很簡短,
// Package math provides basic constants and mathematical functions.
package math
包名
對包中名稱的所有參考都將使用包名完成,因此可以從識別符號中省略該名稱, 例如,如果你正在使用 chubby 包,則不需鍵入 ChubbyFile ,因為客戶端會將其寫為 chubby.ChubbyFile, 相反,命名為 File 的這種方式,客戶端會將它寫為 chubby.File , 避免使用像 util 、 common 、 misc 、 api 、 types 和 interfaces 這樣無意義的包名,
不要Panic
錯誤資訊
即使用 fmt.Errorf("something bad") 而不要使用 fmt.Errorf("Something bad")
包的匯入
避免包重命名匯入,防止名稱沖突;好的包名稱不需要重命名,如果發生命名沖突,則更傾向于重命名最接近本地的包或特定于專案的包,
包匯入按組進行組織,組與組之間有空行,標準庫包始終位于第一組中,
package main
import (
"fmt"
"hash/adler32"
"os"
"appengine/foo"
"appengine/user"
"github.com/foo/bar"
"rsc.io/goversion/version"
)
包的匿名匯入
即 import _ "pkg" 這種匯入陳述句,最好只存在于main.go檔案中
Dot 匯入
package foo_test
import (
. "foo"
)
不要在程式中使用 import .,它將使程式更難閱讀
行內錯誤
不規范寫法
// 查找回傳鍵的值,如果沒有鍵的映射,則回傳空字串,
func Lookup(key string) string
規范寫法
// 查找并回傳鍵的值,如果沒有鍵的映射,則ok = false,
func Lookup(key string) (value string, ok bool)
并有利于寫出更健壯和可讀性更強的代碼:
value, ok := Lookup(key)
if !ok {
return fmt.Errorf("no value for %q", key)
}
return Parse(value)
縮進錯誤處理
要縮進錯誤處理邏輯,不要縮進常規代碼,這樣可以改進代碼的可讀性,讀者可以快速地瀏覽邏輯主干,例如,不要寫:
if x, err := f(); err != nil {
// 錯誤處理
return
} else {
// 使用變數 x
}
相反,應該這樣寫:
x, err := f()
if err != nil {
// 錯誤處理
return
}
// 使用變數 x
這樣寫的好處可以增加可讀性
首字母縮寫
名稱中的單詞是首字母或首字母縮略詞(例如 "URL" 或 "NATO" )需要具有相同的大小寫規則,例如,"URL" 應顯示為 "URL" 或 "url" (如 "urlPony" 或 "URLPony" ),而不是 "Url",舉個例子:ServeHTTP 不是 ServeHttp,對于具有多個初始化 “單詞” 的識別符號,也應當顯示為 "xmlHTTPRequest" 或 "XMLHTTPRequest",
當 "ID" 是 "identifier" 的縮寫時,此規則也適用于 "ID" ,因此請寫 "appID" 而不是 "appId",
protocol buffer 生成的代碼是個例外,對人和對機器的要求不能一樣,人撰寫的代碼要比機器撰寫的代碼保持更高的標準,
介面
總的來說,Go 的介面要包含在使用方的包里,不應該包含在實作方的包里,實作方只需要回傳具體型別(通常是指標或結構體),這樣一來可以將新方法添加到實作中,而不需要擴展重構,
不要在 API 的實作者端定義 "for mocking" 介面;反而是要定義公開的 API,用真實的實作進行測驗,
不要先定義介面再用它,脫離真實的使用場景,我們都不能確定一個介面是否有存在的價值,更別提設計介面的方法了
建議寫法,把介面和介面具體的實作類分開兩個go檔案
package consumer // consumer_func.go
type Thinger interface { Thing() bool }
func Foo(t Thinger) string { … }
package consumer //consumer.go
type defaultThinger struct{ … }
func (t defaultThinger) Thing() bool { … }
func NewThinger() Thinger { return defaultThinger{ … } }
不規范寫法
package producer
type Thinger struct{ … }
func (t Thinger) Thing() bool { … }
func NewThinger() Thinger { return Thinger{ … } }
方法接收者命名
方法接收者的名稱應該反映其身份;通常,其型別的一個或兩個字母縮寫就足夠了(例如用 "c" 或 "cl" 表示 "client" ),不要使用通用名稱,例如 "me","this" 或 "self",這是面向物件語言的典型識別符號,這些識別符號賦予該方法特殊的含義,
方法接收者型別
要是把握不準,就用指標,
變數名稱
Go 中的變數名稱盡可能短為妙,言簡意賅,尤其是對于那些處于有限空間中的區域變數更是如此,例如: 用 c 而不是 lineCount; 用 i 而不是 sliceIndex ,
基本準則:當變數首次被使用時離宣告的位置越遠,變數名稱必須更具描述性,對于方法接收者的名稱來說,一個或者兩個字母就足夠了,普通變數比如 loop indices 、 readers 的名稱用一個字母(i , r)指代就可以,
當然,對于一些邏輯比較復雜的邏輯,或者非常規事物,或者全域變數則需使用更具描述性的名字,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/421621.html
標籤:其他
