命名篇
本篇以開發時從上往下的順序既:開發前約定的基本命名規范、包、常量、變量、結構體、參數、返回值的順序講解了開發中各個環節的命名規范。
2.1 基本命令規范
【規則2.1.1】需要注釋來補充的命名就不算是好命名。
說明:命名應該做到讓人見名知意,好的命名可以讓人節省關注注釋的時間。
【規則2.1.2】使用可搜索的名稱
說明:單字母名稱和數字常量很難從一大堆文字中搜索出來。單字母名稱僅適用於短方法中的本地變量,名稱長短應與其作用域相對應。若變量或常量可能在代碼中多處使用,則應賦其以便於搜索的名稱。
【規則2.1.3】做有意義的區分
說明:要區分名稱,就要以讀者能鑒別不同之處的方式來區分
比如說Product 和 ProductInfo 和 ProductData 沒有區別,NameString 和 Name 沒有區別。
錯誤示例:
type Reader interface {
Read(p []byte) (n int, err error)
}
// 多個函數接口
type WriteFlusher interface {
Write([]byte) (int, error)
Flush() error
}
2.2 項目目錄名
【規則2.2.1】目錄名必須為全小寫單詞,允許加中划線‘-’組合方式,但是頭尾不能為中划線。
例如:
go-sql-driver
hsa-microservice
service-mgr
【建議2.2.2】雖然允許出現中划線,但是盡量避免或少加中划線。
2.3 包名
【原則2.3.1】取名盡量采取有意義的包名,簡單和可閱讀。
【規則2.3.2】包名必須全部為小寫單詞,無下划線,越短越好。盡量不要與標准庫重名。
錯誤示例:
import (
"MyUtil" //包名大寫
"suffix_array" //有下划線
"io/util suffixarray" //不僅長,還是個帶空格的包名
"io/ioutil" //與標准庫重名
)
說明:包名在被導入后,會以 package.Func()方式使用,任何人使用你的包都得敲一遍該包名,因為包名也是類型和函數的一部分
例如buf := new(bytes.Buffer)
就不要取名為 bytes.BytesBuffer
,這樣過於累贅。
【規則2.3.3】禁止通過中划線連接多個單詞的方式來命名包名。
package go-oci8 //編譯錯誤
【建議2.3.4】包名盡量與所在目錄名一致,引用時比較方便。
說明:這是因為在import導入的包是按目錄名來命名的,如果不一致,代碼閱讀者就很困惑。
2.4 文件名
和其它語言一樣,名字在Go中是非常重要的。它們甚至還具有語義的效果:一個名字在程序包之外的可見性是由它的首字符是否為大寫來確定的。因此,值得花費一些時間來討論Go程序中的命名約定。
【規則2.4.1】文件名必須為小寫單詞,允許加下划線‘_’組合方式,但是頭尾不能為下划線。
例如: port_allocator.go
【建議2.4.2】雖然允許出現下划線,但是盡量避免。
說明:如果采用下划線的方式,注意避免跟下面保留特定用法的后綴沖突:
1)測試文件:_test.go
2)系統相關的文件:
_386.go、_amd64.go、_arm.go、_arm64.go、_android.go、_darwin.go、_dragonfly.go、_freebsd.go、_linux.go、_nacl.go、_netbsd.go、_openbsd.go、_plan9.go、_solaris.go、_windows.go、_android_386.go、_android_amd64.go、_android_arm.go、_android_arm64.go、_darwin_386.go、_darwin_amd64.go、_darwin_arm.go、_darwin_arm64.go、_dragonfly_amd64.go、_freebsd_386.go、_freebsd_amd64.go、_freebsd_arm.go、_linux_386.go、_linux_amd64.go、_linux_arm.go、_linux_arm64.go、_linux_mips64.go、_linux_mips64le.go、_linux_ppc64.go、_linux_ppc64le.go、_linux_s390x.go、_nacl_386.go、_nacl_amd64p32.go、_nacl_arm.go、_netbsd_386.go、_netbsd_amd64.go、_netbsd_arm.go、_openbsd_386.go、_openbsd_amd64.go、_openbsd_arm.go、_plan9_386.go、_plan9_amd64.go、_plan9_arm.go、_solaris_amd64.go、_windows_386.go
_windows_amd64.go
【建議2.4.3】文件名以功能為指引,名字中不需再出現模塊名或者組件名。
說明:因為Go包的導入是與路徑有關的,本身已經隱含了模塊/組件信息。
2.5 常量
【規則2.5.1】常量&枚舉名采用大小寫混排的駝峰模式(Golang官方要求),不允許出現下划線
示例:
const (
CategoryBooks = iota // 0
CategoryHealth // 1
CategoryClothing // 2
)
【建議2.5.2】按照功能來區分,而不是將所有類型都分在一組,並建議將公共常量置於私有常量之前
示例:
const (
KindPage = "page"
// The rest are node types; home page, sections etc.
KindHome = "home"
KindSection = "section"
KindTaxonomy = "taxonomy"
KindTaxonomyTerm = "taxonomyTerm"
// Temporary state.
kindUnknown = "unknown"
// The following are (currently) temporary nodes,
// i.e. nodes we create just to render in isolation.
kindRSS = "RSS"
kindSitemap = "sitemap"
kindRobotsTXT = "robotsTXT"
kind404 = "404"
)
【規則2.2.3】如果是枚舉類型的常量,需要先創建相應類型
示例:
type tstCompareType int
const (
tstEq tstCompareType = iota
tstNe
tstGt
tstGe
tstLt
tstLe
)
【建議2.5.4】如果模塊的功能較為復雜、常量名稱容易混淆的情況下,為了更好地區分枚舉類型,可以使用完整的前綴
示例:
type PullRequestStatus int
const (
PullRequestStatusConflict PullRequestStatus = iota
PullRequestStatusChecking
PullRequestStatusMergeable
)
2.6 變量
變量申明
【規則2.6.1】變量命名基本上遵循相應的英文表達或簡寫,在相對簡單的環境(對象數量少、針對性強)中,可以將一些名稱由完整單詞簡寫為單個字母
例如:
- user 可以簡寫為 u
- userID 可以簡寫 uid
- 若變量類型為 bool 類型,則名稱應以 Has, Is, Can 或 Allow 開頭:
var isExist bool
var hasConflict bool
var canManage bool
var allowGitHook bool
只有從其他標准移植過來的常量才和原來保持一致,比如:
-
自定義的 http.StatusOK
-
移植過來的 tls.TLS_RSA_WITH_AES_128_CBC_SHA
變量命名慣例
【規則2.6.2】變量名稱一般遵循駝峰法,並且不允許出現下划線,當遇到特有名詞時,需要遵循以下規則:
- 如果變量為私有,且特有名詞為首個單詞,則使用小寫,如:apiClient
- 其它情況都應當使用該名詞原有的寫法,如 APIClient、repoID、UserID
錯誤示例:UrlArray,應該寫成 urlArray 或者 URLArray
下面列舉了一些常見的特有名詞:
"API","ASCII","CPU","CSS","DNS","EOF",GUID","HTML","HTTP","HTTPS","ID","IP","JSON","LHS","QPS","RAM","RHS"
"RPC", "SLA","SMTP","SSH","TLS","TTL","UI","UID","UUID","URI","URL", "UTF8","VM","XML","XSRF","XSS"
【規則2.6.3】不要使用_來命名變量名,多個變量申明放在一起
正確示例:
var (
Found bool
count int
)
【規則2.6.4】在函數外部申明必須使用var,不要采用:=,容易踩到變量的作用域的問題。
全局變量名
【規則2.6.5】全局變量必須為大小寫混排的駝峰模式,不允許出現下划線。首字母根據作為范圍確定大小寫。
例如:
var Global int //包外
var global int //包內
【建議2.6.6】盡量避免跨package使用全局變量,盡量減少全局變量的使用。
局部變量名
【規則2.6.7】局部變量名必須為大小寫混排,且首字母小寫,不能有下划線。
例如:
result, err := MakeRegexpArray(str)
循環變量
【建議2.6.8】for循環變量可以使用單字母。
2.7 結構體(struct)
【規則2.7.1】struct申明和初始化格式采用多行
定義如下:
type User struct{
Username string
Email string
}
初始化如下:
u := User{
Username: "astaxie",
Email: "astaxie@gmail.com",
}
【規則2.7.2】結構體名必須為大小寫混排的駝峰模式,不允許出現下划線,可被包外部引用則首字母大寫;如僅包內使用,則首字母小寫。
例如:
type ServicePlan struct
type internalBroker struct
【建議2.7.3】結構名建議采用名詞、動名詞為好。
結構體名應該是名詞或名詞短語,如Custome、WikiPage、Account、AddressParser,避免使用 Manager、Processor、Data、Info、這樣的類名,類名不應當是動詞。
*
2.8 接口名
接口命名規則:單個函數的接口名以”er”作為后綴,
【規則2.8.1】接口名必須為大小寫混排,支持包外引用則首字母大寫,僅包內使用則首字母小寫。不能有下划線,整體必須為名詞。
【建議2.8.2】單個函數的接口名以”er”作為后綴。
單個函數的接口名以”er”作為后綴,如Reader,Writer。接口的實現則去掉“er”。除非有更合適的單詞。
例如:
type Reader interface {...}
2.9 函數和方法名
函數
【規則2.9.1】函數名必須為大小寫混排的駝峰模式
函數名必須為大小寫混排的駝峰模式,名字可以長但是得把功能,必要的參數描述清楚,不允許出現下划線。
示例:
func MakeRegexpArrayOrDie // 暴露給包外部函數
func matchesRegexp // 包內部函數
【建議2.9.2】函數名力求精簡准確,並采用用動詞或動詞短
如 postPayment、deletePage、save。並依 Javabean 標准加上 get、set、is前綴。
例如:xxx + With + 需要的參數名 + And + 需要的參數名 + …..
方法
【規則2.9.3】方法接收名必須為大小寫混排,首字母小寫。方法接收者命名要能夠體現接收者對象。
【建議2.9.4】接收者名通常1個或者2個字母就夠,最長不能超過4個字母。
【建議2.9.5】接收者名不要使用me,this 或者 self 這種泛指的名字。
例如:
func (c *Controller) Run(stopCh <-chan struct{})
參考:https://github.com/golang/go/wiki/CodeReviewComments#receiver-names
【建議2.9.6】定義方法時,如果方法內不會直接引用接收者,則省略掉接收者名。
舉例:
func (T) sayHi() {
// do things without T
}
func (*T) sayHello() {
// do things without *T
}
2.10 參數名
【規則2.10】參數名必須為大小寫混排,且首字母小寫,不能有下划線。
例如:
func MakeRegexpArray(str string)
2.11 返回值
【規則2.11.1】返回值如果是命名的,則必須大小寫混排,首字母小寫。
【建議2.11.2】 函數的返回值應避免使用命名的參數。
舉例:
func (n *Node) Bad() (node *Node, err error)
func (n *Node) Good() (*Node, error)
因為如果使用命名變量很容易導致臨時變量覆蓋而引起隱藏的bug。
例外情況:多個返回值類型相同的情況下,使用命名返回值來區分不同的返回參數。
說明:命名返回值使代碼更清晰,同時更加容易讀懂。
舉例:
func getName()(firstName, lastName, nickName string){
firstName = "May"
lastName = "Chen"
nickName = "Babe"
return
}
參考:
https://github.com/golang/go/wiki/CodeReviewComments#named-result-parameters
https://golang.org/doc/effective_go.html#named-results