文章目录
命名篇
本篇以开发时从上往下的顺序既:开发前约定的基本命名规范、包、常量、变量、结构体、参数、返回值的顺序讲解了开发中各个环节的命名规范。
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