1 高质量编程
1.1 注释规范
核心就是要提供额外信息辅助理解
不需要注释实现接口的方法
思考:一般C++/python会提供输入输出,函数功能的说明,且注释比较结构化,Go的看起来像一段文字。
1.2 命名规范
核心就是能提供信息,且彼此不重复不冲突
- 变量
· 缩略词:一般全大写,位于开头且不需要导出时全小写
· 距离使用的地方越远,携带的信息越多,如全局变量
· 函数参数最好能直接表示含义
· 误区
· 长命名的局部变量并不优于单字母
- 函数
· 不需要携带包名的上下文信息,这样子每部分命名都能体现相应的信息
· 函数的返回类型与包名一致时,可以省略返回类型信息而不导致歧义;
不一致时,函数名需携带类型信息
示例:选Serve即可,调用时一般是http.Serve
- 包
· 只由小写字母组成,不包含大写字母和下划线
· 简短但包含信息
· 不与标准库同名
· 不使用常用变量名,如bufio而不是buf
· 不使用复数
1.3 控制流程
- 避免嵌套,保证流程清晰 -> 应该理解为减少分支
如果两个分支都包含return,则可以去除冗余的else
if 条件{
...
return
}
//else{
return
- 尽量保持正常路径代码为最小缩进 -> 理解为减少层次嵌套
优先处理错误异常情况,减少嵌套
1.4 错误和异常处理
1.4.1 简单错误
仅出现一次,在其他地方不需要捕获
一般创建:errors.New("msg")
需要格式化:fmt.Errorf
1.4.2 复杂错误(Go1.13引入)
- 错误链:处理方式是wrap和unwrap
wrap:一个错误嵌套另一个错误,形成错误的跟踪链
在fit.Errorf中使用:%w关键字将该错误加入到错误链
errors.Is
判定范围为整条链,不同于==只能判定单一错误
data, err = lockedfile.Read(targ)
if errors.Is(err, fs.ErrNotExist) {
return []byte{}, nil
}
return data, err
-
errors.As获取特定种类的错误
与Is的区别:取出特定错误的命令
if _, err := os.Open("non-existing"); err != nil{ var pathError *fs.pathError if errors.As(err, &pathError) { //here pathError with explicit error path fmt.Println("Failed at path:", pathError.Path) } else { fmt.Println(err) } }
1.4.3 panic和recover
-
panic
- 不建议在业务代码中使用
- 调用函数不包含
recover会造成程序崩溃 - 如果是可以被屏蔽或解决的问题,建议使用
error代替 - 建议使用时机:在程序启动阶段发生不可逆转错误,在
main或init中使用panic
-
recover
-
只能在被defer的函数中使用
-
嵌套无法生效
-
只在当前goroutine中生效
-
defer的执行是后进先出的机制
协程遇到panic时,遍历本协程的defer链表,并执行defer。在执行defer过程中,遇到recover则停止panic,返回recover处继续往下执行。如果没有遇到recover,遍历完本协程的defer链表后,向stderr抛出panic信息。从执行顺序上来看,实际上是按照先进后出的顺序执行defer
package main import "fmt" func main() { defer_call() } func defer_call() { defer func() { fmt.Println("one") }() defer func() { fmt.Println("two") }() defer func() { fmt.Println("three") }() panic("触发异常") } /*output is three two one panic: 触发异常 */func main() { if true { defer fmt.Println("1") } else { defer fmt.Println("2") } defer fmt.Println("3") } /* 3 1 */需要更多的上下文信息,可以在recover后在log中记录当前的调用栈
func (t *treeFS) Open(name string) (f fs.File, err Error) { defer func() { if e := recover(); e != nil { f = nil err = fmt.Errorf("gifts panic: %v\n%s", e, debug.Stack()) } }() //... }总结
recover的生效范围:当前goroutine的被defer的函数中生效 -
1.4.5 小结
error简明扼要的提供错误信息,方便定位
panic用于真正异常的情况