编码规范
原则
- 简单性
- 可读性
- 生产力
代码格式
使用gofmt或者goimports自动格式化代码
gofmt: go语言官方提供的工具,能够自动化go语言代码为官方统一风格
goimports: go语言官方提供的工具,实际上等于gofmt加上依赖包管理,自动增删依赖的包引用、将依赖包按字母排序并分类
注释
作用
- 解释代码的作用
- 解释代码是如何做的
- 解释代码实现的原因
- 解释代码的限制条件
必须使用注释的情况
- 包中声明的每个公共的符号:变量、常量、函数以及结构
- 任何既不明显也不简短的公共功能
- 库中的任何函数
注意: 实现接口的方法不需要注释
命名规范
变量
- 简洁
- 缩略词全大写,但当其位于变量开头并且不要导出时,是用小写,例如:ServeHTTP
- 变量距离其被使用的地方越远,则需要携带越多的上下文信息
函数
- 函数名不携带包名的上下文信息
- 尽量简短
- 当包名为xxx的包某个函数返回类型为Xxx时,可以省略类型信息而不导致歧义
- 当包名为xxx的包某个函数返回类型为T时,可以在函数名中加入类型信息
包
- 只由小写字母组成
- 简短并包含一定的上下文信息
- 不能与标准库同名
- 不使用常量名作为包名
- 使用单数而不是复数
控制流程
- 避免嵌套,保持正常流程清晰
- 如果两个分支中都包含return语句,则可以去除冗余的else
- 尽量保持正常代码路径为最小缩进,优先处理错误情况/特殊情况,并尽早返回或继续循环来减少嵌套,增加可读性
错误和异常处理
简单错误
简单错误指的是仅出现一次的错误,并且其他地方不需要捕获该错误
- 优先使用errors.New来创建匿名变量来直接表示简单错误
- 如果有格式化的需求,使用fmt.Errorf
go
复制代码
go
复制代码
func defaultCheckRedirect(req *Request, via []*Request) error{
if len(via) >=10{
return errors.New("stopped after 10 redirects")
}
return nil
}
错误的Wrap和Unwrap
- 错误的Wrap实际上是提供了一个error嵌套另一个error的能力,从而生成一个error的跟踪链
- 在fmt.Errorf中使用
%w可以将一个错误关联至错误链中
错误判定
- 判定一个错误是否为特定错误使用errors.Is,可以判定错误链上的所有错误是否含有特定的错误
- 在错误链上获取特定种类的错误使用errors.As
其他方法
-
panic
- 不建议在业务代码中使用panic
- 当程序启动阶段发生不可逆转的错误时,可以在init或main函数中使用panic
-
recover
- 只能在被defer的函数中使用
- 嵌套无法生效
- 只在当前goroutine中生效
- defer的语句是后进先出
- 如果需要更多的上下文信息,可以recover后再log中记录当前的调用栈
go
复制代码
go
复制代码
func (t *treeFS) Open(name string) (f fs.File, err error) {
defer func() {
if e := recover(); e != nil {
f = nil
err = fmt.Errorf("gitfs panic: %v\n%s", e, debug.Stack())
}
}
}
//debug.Stack()包含的调用堆栈信息方便定位具体问题代码