# Golang编程模式：错误处理

## 包装错误

开发过程中一般我们推荐包装一下错误，而不是干巴巴地把`err`给返回到上层，我们需要把一些执行的上下文加入。

通常来说，我们会使用 `fmt.Errorf()`来完成这个事，比如：

```go
if err != nil {
   return fmt.Errorf("something failed: %v", err)
}
```

另外，在Go语言的开发者中，更为普遍的做法是将错误包装在另一个错误中，同时保留原始内容：

```go
type authorizationError struct {
    operation string
    err error   // original error
}

func (e *authorizationError) Error() string {
    return fmt.Sprintf("authorization failed during %s: %v", e.operation, e.err)
}
```

当然，更好的方式是通过一种标准的访问方法，这样，我们最好使用一个接口，比如 `causer`接口中实现 `Cause()` 方法来暴露原始错误，以供进一步检查：

```go
type causer interface {
    Cause() error
}

func (e *authorizationError) Cause() error {
    return e.err
}
```

## 最佳实践

有个好消息：有一个第三方的错误库（[github.com/pkg/errors](https://github.com/pkg/errors)）帮我们实现了以上功能，而且这个库，在各种 `golang` 项目中广泛使用，所以这个基本上来说就是事实上的标准了。

列举几个常见的项目：

* [k8s.io/kubernetes](https://deps.dev/go/k8s.io%2Fkubernetes/v1.5.0-alpha.2)
* [github.com/astaxie/beego](https://deps.dev/go/github.com%2Fastaxie%2Fbeego/v1.12.3)
* [github.com/containerd/containerd](https://deps.dev/go/github.com%2Fcontainerd%2Fcontainerd/v1.5.7)
* [github.com/docker/docker](https://deps.dev/go/github.com%2Fdocker%2Fdocker/v1.13.1)
* [github.com/go-kit/kit](https://deps.dev/go/github.com%2Fgo-kit%2Fkit/v0.9.0)
* [github.com/google/cadvisor](https://deps.dev/go/github.com%2Fgoogle%2Fcadvisor/v0.47.3)
* [github.com/hashicorp/terraform](https://deps.dev/go/github.com%2Fhashicorp%2Fterraform/v0.15.3)
* [github.com/influxdata/influxdb](https://deps.dev/go/github.com%2Finfluxdata%2Finfluxdb/v1.11.1)
* [github.com/micro/go-micro/v2](https://deps.dev/go/github.com%2Fmicro%2Fgo-micro%2Fv2/v2.9.1)
* [github.com/uber-go/zap](https://deps.dev/go/github.com%2Fuber-go%2Fzap/v1.0.0-rc.1)

信息来源：<https://deps.dev/go/github.com%2Fpkg%2Ferrors/v0.9.1/dependents，有兴趣的同学可以访问查看>

代码示例如下：

```go
import "github.com/pkg/errors"

//错误包装
if err != nil {
    return errors.Wrap(err, "read failed")
}

// Cause接口
switch err := errors.Cause(err).(type) {
case *MyError:
    // handle specifically
default:
    // unknown error
}
```

## 参考文章

* <https://coolshell.cn/articles/21140.html>


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://marswang.gitbook.io/blog/golang/golang-bian-cheng-mo-shi-cuo-wu-chu-li.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
