高质量GO编程 | 青训营笔记

95 阅读3分钟

这是我参与「第三届青训营 -后端场」笔记创作活动的的第1篇笔记

高质量编程简介

编写的代码准确可靠、简洁清晰:简单、可读、生产力

  • 边界条件考虑完备
  • 异常情况处理
  • 易读易维护

编码规范

代码格式

gofmt自动格式化代码

GO语言官方工具,能够自动格式化GO

goimports:gofmt + 依赖包管理

注释

注释该有的4个作用:

  • 解释代码作用
  • 解释代码如何做
  • 解释代码实现的原因
  • 解释代码什么情况下出错

公共符号始终要注释:

  • 包中声明的每个公共符号:变量、常量、函数、结构都需要
  • 不明显也不简短的公共功能
  • 库中的任何函数
  • 例外:不需要注释实现接口的方法,如下:
//Read implents the io.Reader interface
func (r *Filereader) Read(buf []byte) (int, error)

命名规范

变量:

  • 简洁
  • 缩略词全大写,但当其位于变量开头且不需要导出时,使用全小写,例如使用ServeHTTP而不是ServeHttp;使用XMLHTTPRequest而不是xmlHTTPRequest
  • 变量距离其被使用的地方越远,则需要携带越多的上下文信息

函数:

  • 不携带包名的上下文信息
  • 尽量简短
  • 当名为 foo 的包某个函数返回类型 Foo 时,可以省略类型信息而不导致歧义
  • 当名为 foo 的包某个函数返回类型 T 时(T 并不是 Foo),可以在函数名中加入类型信息

包:

  • 只由小写字母组成
  • 简短并包含一定的上下文信息,如schematask
  • 不要与标准库同名,如不要使用schemaorstrings

控制流程

避免嵌套,保持正常流程清晰,如两个分支都包含return,则可以去除冗余的else

尽量保持正常代码路径为最小缩进,优先处理错误情况/特殊情况,尽早返回或继续循环来减少嵌套

错误和异常处理

简单错误(仅出现一次的错误)

优先使用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.ls

该方法可以判定错误链上的所有错误是否含有特定错误

在错误链上获取特定种类的错误,使用errors.As

panic

用于真正异常情况

调用函数不包含 recover会造成程序崩溃

recover

只能在被 defer 的函数中使用

嵌套无法生效

只在当前goroutine生效

如果需要更多的上下文信息,可以recover后在log中记录当前的调用栈