Go补基础|青训营

105 阅读3分钟

三、高质量编程与性能调优实践

3.1 编码规范

3.1.1代码格式:

-- dofmt(golang内置);-- goimports(gofmt基础上增加了依赖包管理)

3.1.2 注释:

解释代码功能、实现过程、为什么这么做(外部因素,提供额外上下文)、什么情况会出错(限制条件)

  • 包中声明的每个公共符号(变量、常量、函数、结构)

    • 例外:不需要注释实现接口的方法
  • 不明显、不简短的公共功能
  • 库中的任何函数

3.1.3 命名规范:

  • 变量

    • 缩略词全大写,但当位于变量开头且不需要导出时,使用全小写:如ServerHTTP,而不是ServerHttp
    • 变量距离被使用的地方越远,要携带越多上下文信息,对外提供时需要更多信息量
    • 尽量简洁
  • function

    • 不携带包名的上下文信息,因为包名和函数名总是携带出现的
    • 简短
    • 函数返回类型名字同包名时省略类型信息,使无歧义;不同时可在函数名中加入类型信息
  • package

    • 只用小写字母组成
    • 简洁并包含一定上下文
    • 不与标准库和常用变量名重名
    • 使用单数而不是复数
    • 谨慎地使用缩写,fmt > format

3.1.4 控制流程:

线性原理,尽量走直线,避免嵌套分支

  • 避免嵌套:if-else中若都包含return语句,去除冗余的else
 //bad
 if foo{
     return x
 }else{
     return nil
 }
 ​
 //good
 if foo{
     return x
 }//若有新增情况,直接在此插入
 return nil
  • 尽量保持正常代码路径为最小缩进:优先处理错误情况或特殊情况,尽早返回或继续循环来减少嵌套
 //Good
 func OneFunc() error{
     if err := doSomething; err != nil{
         return err
     }
     if err := doAnotherThing; err != nil{
         return err
     }
     //若有新增情况,直接在此插入
     return nil // normal case
 }

3.1.5 异常处理

  • 简单错误:仅出现一次的错误,且在其他地方不需要捕捉该错误

    • 优先使用 errors.New 来创建匿名变量来直接表示简单错误,如有格式化需求,使用fmt.Errorf
     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 将一个错误关联至错误链中
     list,_,err:=c.GetBytes(cache.Subkey(a.actionID,"srcfiles"))
     if err != nil{
         return fmt.Errorf("reading srcfiles list: %w",err)
     }
    
  • 错误判定:

    • 判定是否为特定错误:errors.is ;不同于 == ,可判定错误链上的所有错误是否含有特定错误
    • 从错误链上获取特定种类错误的内容:errors.As 。方便定位分析问题
     if _,err := os.Open("non-existing");err != nil{
         var pathError *fs.PathError
         if errors.As(err,&pathError){
             fmt.Println("Failed at path:",pathError.Path)
         }else{
             fmt.Println(err)
         }
     }
    
  • panic (更严重,程序无法工作):

    • 不建议在业务代码中使用

      • 调用函数不包含 recover 会造成程序崩溃
      • 若问题可以被屏蔽或解决,建议使用 error 代替 panic
    • 当程序启动阶段发生不可逆错误时,可以在 init 或 main 函数中使用 panic

  • recover:

    • 引用的库出现 bug 时