这是我参与「第三届青训营 -后端场」笔记创作活动的的第3篇笔记
1. 编码规范
1.1 代码格式
- 使用gofmt和goimports将代码进行格式化,能自动格式化Go语言代码为官方统一风格
1.2 注释
注释应该做的:
1.2.1 注释应该解释代码作用
适合注释功能公共符号,当函数名就已经完全表达了函数的意思的时候就可以不用写注释
// Open opens the named file for reading. If successful, mehods on
// the returned file can be used for reading; the associated file
// descriptor has made O_RDONLY.
// If there is an error, it will be of type *PathError
func Open(name string) (*File, error) {
return OpenFile(name, O_RDONLY, 0)
}
// 没有必要的注释
// Returns true if the table connot hold any more entries
func IsTableFull() bool
1.2.2 注释应该解释代码如何做的
对代码中复杂的,并不明显的逻辑进行说明,适合注释实现过程
// Add the Referer header from the most recent
// request URL to the new one, if it's not https->http
if ref := refererFroURL(reqs[len(reqs)-1]).URL, req.URL); ref != "" {
req.Header.Set("Referer", ref)
}
1.2.3 注释应该解释代码实现的原因
注释代码的外部因素, 这些因素脱离上下文后通常难以理解,提供额外的上下文
以下示例有一行shouldRedirect = false语句,如果没有注释,无法清楚地明白为什么会设置false
switch resp.StatusCode {
// ...
case 307, 308:
redirectMethod = req.Method
shouldRedirect = true
includeBody = true
if ireq.GetBody == nil && ireq.outgoingLength() != 0 {
// We had a request body, and 307/308 require
// re-sending it, but GetBody is not defined, So just
// return this response to the user instead of an
// error, like we did in Go 1.7 and earlier.
shouldRedirect = false
}
}
1.2.4 注释应该解释代码什么情况会出错
提醒使用者一些潜在的限制条件或会无法处理的情况
可以说明是否存在性能隐患,输入的限制条件,可能存在哪些错误情况
// parseTimeZone parses a time zone string and returns its length. Time zones
// are human-generated and unpredictable. We can't do precise error checking.
// On the other hand, for a correct parse there must be a time zone at the
// beginning of the string, so it's almost always true that there's one
// there. We look at the beginning of the string for a run of upper-case letters.
// If there are more than 5, it's an error.
// If there are 4 or 5 and the last is a T, it's a time zone.
// If there are 3, it's a time zone.
// Otherwise, other than special cases, it's not a time zone.
// GMT is special because it can have an hour offset.
func parseTimeZone(value string) (length int, ok bool)
1.2.5 公共符号始终要注释
- 包中申明的每个公共的符号:变量、常量、函数以及结构都需要添加注释
- 任何既不明显页不简短的公共功能必须予以注释
- 无论长度或复杂长度如何,对库中的任何函数都必须进行注释
1.2.6 注释总结
- 注释也作为代码的一部分,注释主要提供的内容为代码的作用、使用注意事项、使用用例、为什么这样编写也就是提供额外的上下文,好的注释能让阅读代码的时间大大降低,在后续对代码进行维护和改造时能够让程序员有更大的把握改造一些复杂的代码而不影响现有的功能;如果方法名已经明确了相应的功能且方法较为简单如
Set()、Get()这种类似的方法,则可以不编写注释,在实现某个接口的方法时也可以不编写功能相关的注释
2. 命名规范
2.1 包名
- 小写字母开头且尽量使用单数,如
util而非utils - 避免与系统包名和关键字重复,如需要创建一个保存常量的包,取名
constant而非const - 在能符合大部分人认同的简写中可以使用简写,如
format简化成fmt - 当涉及到多个单词时,采用分级目录而非下划线分离,或全小写字母连在一起,如
util下一级目录convert,errcode这种包名
2.2 变量
- 采用驼峰命名法
- 对于常用简写如HTTP、ID、API这种原型为多个单词的简写情况
-
- 若可见性为包外可见且为开头,则命名为
HTTPServer - 若可见性为包内可见且为开头,则命名为
httpServer - 如果不为多个单词的开头单词,则命名采用原命名
userID
- 若可见性为包外可见且为开头,则命名为
2.3 方法
- 方法名与变量命名相同,但方法命名与包名也有关联
- 当包名已经展现出上下文信息时,在方法名中不携带包名提供的上下文信息,如包名为
book,这时包中的方法名为Search()而不用命名为SearchBook(),因为包名已经携带了相应的上下文;但在方法命名中需要携带包名没有提供的上下文信息,如time包中的Parse()为解析时间的,会返回一个Time对象,而需要获得一个Duration时time包中解析持续时间的方法应该命名为ParseDuration(),这样携带了包名没有提供的信息。