持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情
本节继续扩展下关于error的一些编码规则吧,只是遇到感觉好的一些点,官方是没有统一的规范约束滴。
- 处理所有含有err的返回值,不使用_忽略错误返回值
反面例子
buf, _ := json.Marshal(e)
正面例子
// Error decodes response error for a string of golang dubbo.
buf, err := json.Marshal(e)
if err != nil {
msg, retryErr := json.Marshal(err.Error())
if retryErr != nil {
msg = []byte("jsonrpc2.Error: json.Marshal failed")
}
return fmt.Sprintf(`{"code":%d,"message":%s}`, -32001, string(msg))
}
- 多次重复使用的错误,可以分组统一定义
// error type group A
(
ErrA = errors.New("A")
ErrAA= errors.New("AA")
ErrAAA = errors.New("AAA")
...
)
// error type group B
(
ErrB = errors.New("B")
ErrBB = errors.New("BB")
...
)
- 失败的原因只有一个时或者当函数的error返回值始终是nil时,不使用error
**反例:**
func (self *AgentContext) CheckHostType(hostType string) error {
switch hostType {
case "virtual_machine":
return nil
case "bare_metal":
return nil
}
return ErrInvalidHostType
}
**正例:**
func (self *AgentContext) IsValidHostType(hostType string) bool {
return hostType == "virtual_machine" || hostType == "bare_metal"
}
- error应放在返回值类型列表的最后
func NewConfig() (*Config, error) {
data, err := bootstrapConfigFromEnvVariable()
if err != nil {
return nil, fmt.Errorf("xds: Failed to read bootstrap config: %v", err)
}
dubbogoLogger.Debugf("Bootstrap content: %s", data)
return NewConfigFromContents(data)
}
- 巧用defer错误后清理资源
**反面例子**
func New() (_ *Controller, retErr error) {
ret := &Controller{
streamCh: make(chan grpc.ClientStream, 1),
watchMap: make(map[resource.ResourceType]map[string]bool),
versionMap: make(map[resource.ResourceType]string),
nonceMap: make(map[resource.ResourceType]string),
lrsClients: make(map[string]*lrsClient),
}
builder1, err := builder1(resource1)
if err != nil {
return nil, fmt.Errorf("failed to build resource1 {%s}: %v", "info1", err)
}
builder2 := builder2(resource2)
if builder2 == nil {
closeResource1()
return nil, fmt.Errorf("failed to build resource2 {%s}: %v", "info2", err)
}
builder3, err := builder3(resource3)
if err != nil {
closeResource1()
closeResource2()
return nil, err
}
go ret.run(ctx)
return ret, nil
}
**正面例子:**
// New creates a new controller.
func New() (_ *Controller, retErr error) {
ret := &Controller{
streamCh: make(chan grpc.ClientStream, 1),
watchMap: make(map[resource.ResourceType]map[string]bool),
versionMap: make(map[resource.ResourceType]string),
nonceMap: make(map[resource.ResourceType]string),
lrsClients: make(map[string]*lrsClient),
}
defer func() {
if retErr != nil {
// close all resources and ret
ret.Close()
closeResource1()
closeResource2()
closeResource3()
}
}()
builder1, err := builder1(resource1)
if err != nil {
return nil, fmt.Errorf("failed to build resource1 {%s}: %v", "info1", err)
}
builder2 := builder2(resource2)
if builder2 == nil {
return nil, fmt.Errorf("failed to build resource2 {%s}: %v", "info2", err)
}
builder3, err := builder3(resource3)
if err != nil {
return nil, err
}
go ret.run(ctx)
return ret, nil
}
- 因为消息可能发生嵌套wrap场景,为了更好看错误消息应以小写字母开头,不应以.结尾
反面例子
ErrReadFailed := errors.New("Could not find file")
正面例子
ErrReadFailed := errors.New("could not find file")