diff --git a/README.md b/README.md index 1d1d432..cc13c37 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ Go tips from [Phuong Le](https://twitter.com/func25). | 35 | | | | 36 | | | | 37 | | | -| 38 | | | +| 38 | Make your errors clear with fmt.Errorf, don't just leave them bare | smallnest | | 39 | | | | 40 | | | | 41 | | | diff --git a/src/038.md b/src/038.md new file mode 100644 index 0000000..7daaaf8 --- /dev/null +++ b/src/038.md @@ -0,0 +1,44 @@ +# Tip #38 使用 fmt.Errorf 使你的错误信息清晰明了,不要让它们过于赤裸。 + +> 原始链接:[Golang Tip #38: Make your errors clear with fmt.Errorf, don't just leave them bare.](https://twitter.com/func25/status/1764265328165753176) +> + +在 Go 语言中,错误被当成值来处理。我们采用返回错误而非抛出错误的方式: + +![](./images/038/1.png) + + +仅返回错误而不提供任何额外详情会导致难以确定错误来源及为何发生。 + +这会使调试错误和处理错误变得更加困难。 + +**使用 `fmt.Errorf` 和 `%w` ** + +Go 1.13 版本引入了一种在保留原始错误的同时为其添加更多信息的方法,这就是通过 `fmt.Errorf` 函数配合 `%w` 符号来实现。 + +它会将错误包装起来,以便您在后续需要时能够深入探究: +![](./images/038/2.png) + +> “我还是没看出这样做的好处,反正最后都只是一个错误。” + +让我们通过一个例子来看看添加详细信息的重要性: +![](./images/038/3.png) + + +下面哪一项提供了更多信息? +- "Failed to retrieve resource: Authorization check failed: User 123 does not exist: mongo: no documents in result" +- "Failed to retrieve resource: mongo: no documents in result" + +第一种表述清楚地显示出问题起始于一个不存在的用户,导致了操作失败。而第二种错误信息则未能帮助我们判断问题根源是在用户还是资源上。 + +如果没有这些细节信息,我们可能会错过关于到底哪里出错的重要线索。 + +另外,通过使用 `errors.Is()` 方法,我们可以精准地定位错误的确切类型: +![](./images/038/4.png) + + + +> @thedenisnikulin 提供了额外的建议,我们可以进一步改进错误处理方式。 +> +> "failed to do X: %w" is bad when you have deeply wrapped errors +better write "doing X: %w" diff --git a/src/066.md b/src/066.md index e76b63e..ad3e406 100644 --- a/src/066.md +++ b/src/066.md @@ -11,7 +11,7 @@ 现在,我们应该熟悉使用 `fmt.Errorf` 函数以及 `%w` 来包裹(wrap)错误的做法: -![](./images/066/1.jpeg) +![](./images/066/1.png) 通常情况下,我们可能会得到一个像这样的长错误消息: @@ -21,7 +21,7 @@ 因此,这里有一种更好的做法: -![](./images/066/2.jpeg) +![](./images/066/2.png) 注意到不同之处了吗? diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 4f99d99..56e81c7 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -13,6 +13,7 @@ - [Tip #12 使用 crypto/rand 生成密钥,避免使用 math/rand](./012.md) - [Tip #13 使用空切片还是更好的NIL切片](./013.md) - [Tip #27 原地过滤](./027.md) +- [Tip #38 使用 fmt.Errorf 使你的错误信息清晰明了,不要让它们过于赤裸](./038.md) - [Tip #44 有意地使用Must函数来停止程序](./044.md) - [Tip #47 表驱动测试,测试集和并行运行测试](./047.md) - [Tip #71 用泛型让 sync.Pool 类型安全](./071.md) diff --git a/src/images/038/1.png b/src/images/038/1.png new file mode 100644 index 0000000..25e99c5 Binary files /dev/null and b/src/images/038/1.png differ diff --git a/src/images/038/2.png b/src/images/038/2.png new file mode 100644 index 0000000..a7c4034 Binary files /dev/null and b/src/images/038/2.png differ diff --git a/src/images/038/3.png b/src/images/038/3.png new file mode 100644 index 0000000..42adaa9 Binary files /dev/null and b/src/images/038/3.png differ diff --git a/src/images/038/4.png b/src/images/038/4.png new file mode 100644 index 0000000..beccb18 Binary files /dev/null and b/src/images/038/4.png differ