这是我参与「第五届青训营 」伴学笔记创作活动的第6天。
4.控制流程
- 避免嵌套,保持正常流程清晰,例如:如果两个分支中都包含return语句,则可以去除冗余的else
- 尽量保持正常代码路径为最小缩减,优先处理错误情况/特殊情况,尽早返回或继续循环来减少嵌套
5.错误和异常处理
简单错误
- 简单错误指仅出现一次的错误,且在其他地方不需要捕获该错误
- 优先使用errors.News来创建匿名变量来直接表示简单错误
- 如有格式化需求,使用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关键字将一个错误关联至错误链中
return fmt.Errorf("return srcfiles list: %w", err)
错误判定
// 判断一个错误是否为特定错误
// 不同于使用==,该方法判定错误链上所有错误是否包含特定的错误
error.Is(err, fs.ErrNotExist)
//在错误链上获取特定种类的错误
errors.As(err, &pathError)
panic
recover
在当前goroutine的被defer的函数中生效。
defer语句会在函数返回前调用。
多个defer语句运行顺序是后进先出。
二、性能优化建议
1.Benchmark
go test -bench=. -benchmen
2.Slice
尽可能在使用make()初始化内存时提供容量信息。
3.Map
- 不断向map添加元素会触发扩容
- 提前分配好空间可以减少内存拷贝和Rehash的消耗
- 建议根据实际需求提前预估需要的空间
4.字符串处理
使用 + 拼接性能最差,strings.Builder,bytes.Buffer 相近,strings.Buffer 更快。
分析:
- 字符串在Go语言中是不可变类型,占用内存大小固定
- 使用 + 每次会重新分配内存
- strings.Builder,bytes.Buffer 底层都是 []byte 数组
- 内存扩容策略,不需要每次拼接重新分配内存
- bytes.Buffer转化为字符串时重新申请一块空间
- strings.Builder直接将底层的[]byte转换成字符串类型返回
5.空结构体
- 空结构体struct{}实例不占据内存空间
- 可作为各种场景下的占位符使用
// 实现Set,可以考虑用map代替
// 对于这个场景,只需用map的键,不需要值
func EmptyStructMap(n int) {
m := make(map[int]struct{})
for i := 0; i < n; i++ {
m[i] = struct{}{}
}
}