编码规范| 青训营笔记

121 阅读3分钟

编码规范

原则

  • 简单性
  • 可读性
  • 生产力

代码格式

使用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()包含的调用堆栈信息方便定位具体问题代码