编码规范和性能优化 | 青训营笔记

82 阅读3分钟

高质量编程

  • 边界条件
  • 异常情况处理,稳定性表示
  • 易读易维护

编程原则

  1. 简单性
  • 消除多余的复杂性
  • 不理解的代码无法修复改进
  1. 可读性
  • 编写可维护代码的第一步是确保代码可读
  1. 生产力
  • 团队整体工作效率

编程规范

  • 代码格式 (推荐使用 gofmt 自动格式化代码)
有关gofmt的更多信息,请参见“go doc cmd/gofmt”。

用法:
    gofmt [flags] [path ...]

The flags are:
  	-cpuprofile string
        将CPU配置文件写入此文件
    -d
        不将重新格式化的源打印到标准输出。
		如果一个文件的格式与gofmt的不同,则将差异部分打印到标准输出。
    -e
        打印所有(包括虚假)错误。
    -l
        不将格式化的源打印到标准输出。
		如果文件的格式与 gofmt 不同,则将其名称打印到标准输出。
    -r rule(string)
        在重新格式化之前,对源应用重写规则(例如,'a[b:len(a)] -> a[b:]')
    -s
        尝试简化代码(在应用重写规则后,如果有的话)。
    -w
       	不将重新格式化的源打印到标准输出。
       	如果文件的格式与 gofmt 不同,则用 gofmt 的版本覆盖它。
	如果在覆盖期间发生错误,原始文件将从自动备份中恢复

  • 注释

  • 命名规范

      变量:缩略词全大写;变量距离使用的地方越远,越需要携带更多的上下文信息
      函数:函数名不携带包名的上下文信息;在返回类型T时,可以在函数名中加入类型
      包:只有小写字母组成,不包含大写字母和下划线;不要与标准库同名;不使用常用变量名给包命名
    
  • 控制流程

    尽量保持正常代码路径为最小缩进

  • 错误和异常处理

错误判定:

判定一个错误是否为特定错误,使用 errors.Is
不同于使用 == ,使用该方法可以判定错误链上的所有错误是否含有特定的错误
在错误链中获取特定种类的错误,使用errors.As

panic:

不建议在业务代码中使用panic
若问题可以被屏蔽或解决,建议使用error代替panic
当程序启动阶段发生不可逆转的错误时,可以在init或main函数中使用panic

recover:

只能在defer函数中使用
嵌套无法生效
只能在当前goroutine生效
defer的语句时后进先出

性能优化建议

  1. 推荐使用【Benchmark】

benchmark函数注意事项:

benchmark函数一般以Benchmark开头
benchmark函数也是test case之一,也会受TestMain限制
benchmark的case一般会跑b.N次,而且每次执行都会如此
在执行过程中会根据实际case的执行时间是否稳定会增加b.N的次数以达到稳态
    go test -bench=. -benchmen
  1. slice 预分配内存
  • 尽可能在使用make()初始化切片时提供容量信息
  • 在已有切片基础上创建切片,不会创建新的底层数组
  • 可使用 copy 代替 re-slice
  1. map 预分配内存

  2. 使用strings.Builder

  • 使用 + 拼接性能最差,且每次都会重新分配内存
  • strings.Builder底层是byte数组
  1. 空结构体
  • 空结构体struct{}实例不占据任何的内存空间
  • 可作为各种场景下的占位符使用
  1. atomic包
  • 锁的实现是通过操作系统来实现,属于系统调用
  • atomic操作是通过硬件实现,效率比锁高
  • sync.Mutex 应该用来保护一段逻辑,不仅仅用于保护一个变量
  • 对于非数值操作,可以使用atomic.Value,能承载一个interface{}