「Go工具箱」一个简单、易用的多错误管理包:go-multierror

yudotyang · · 6129 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

<section id="nice" data-tool="mdnice编辑器" data-website="https://www.mdnice.com" style="padding: 0 10px; word-spacing: 0px; word-wrap: break-word; text-align: left; line-height: 1.6; letter-spacing: .034em; color: rgb(63, 63, 63); font-size: 16px; word-break: all; font-family: Optima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif;"><p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;"><img src="https://cdn.nlark.com/yuque/0/2022/webp/25702311/1666141643780-b07ccc05-0268-4117-8aa0-9fbc618e2662.webp#clientId=uf15c8910-5d7f-4&amp;crop=0&amp;crop=0&amp;crop=1&amp;crop=1&amp;from=ui&amp;id=u6f09ba91&amp;margin=%5Bobject%20Object%5D&amp;name=%E7%99%BD%E6%B5%B7%E8%B1%9A.webp&amp;originHeight=600&amp;originWidth=800&amp;originalType=binary&amp;ratio=1&amp;rotation=0&amp;showTitle=false&amp;size=20650&amp;status=done&amp;style=none&amp;taskId=ua004faf0-ee8e-426f-8550-65748394e11&amp;title=" alt="白海豚.webp" style="display: block; margin: 0 auto; max-width: 100%; border-radius: 4px; margin-bottom: 25px;"> 大家好,我是渔夫子。本号新推出「Go 工具箱」系列,意在给大家分享使用 go 语言编写的、实用的、好玩的工具。</p> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">今天给大家推荐的是一个多错误管理包工具:go-multierror。</p> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">该包可以将多个错误合并成一个标准的 error,使得多个错误管理变得更容易。同时,该包和 go 标准库中的 error 包完全兼容,包括 As、Is 和 Unwrap 函数。</p> <h2 data-tool="mdnice编辑器" style="padding: 0px; font-weight: bold; color: black; font-size: 22px; display: block; text-align: center; background-image: url(https://files.mdnice.com/mountain_2.png); background-position: center center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 63px; margin-top: 38px; margin-bottom: 10px;"><span class="prefix" style="display: none;"></span><span class="content" style="text-align: center; display: inline-block; height: 38px; line-height: 42px; color: rgb(60, 112, 198); background-position: left center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 63px; margin-top: 38px; font-size: 18px; margin-bottom: 10px;">小档案</span><span class="suffix"></span></h2> <section class="table-container" data-tool="mdnice编辑器" style="overflow-x: auto;"><table style="display: table; text-align: left;"> <thead> <tr style="border: 0; border-top: 1px solid #ccc; background-color: white;"> <th style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-weight: bold; background-color: #f0f0f0; font-size: 14px; min-width: 85px;"><strong style="font-weight: bold; line-height: 1.75em; color: rgb(74,74,74);"><em style="font-style: italic; color: black;">go-multierror 小档案</em></strong></th> <th style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-weight: bold; background-color: #f0f0f0; font-size: 14px; min-width: 85px;"></th> <th style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-weight: bold; background-color: #f0f0f0; font-size: 14px; min-width: 85px;"></th> <th style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-weight: bold; background-color: #f0f0f0; font-size: 14px; min-width: 85px;"></th> </tr> </thead> <tbody style="border: 0;"> <tr style="border: 0; border-top: 1px solid #ccc; background-color: white;"> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"><strong style="font-weight: bold; line-height: 1.75em; color: rgb(74,74,74);">star</strong></td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;">1.7k</td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"><strong style="font-weight: bold; line-height: 1.75em; color: rgb(74,74,74);">used by</strong></td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;">38.6k</td> </tr> <tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;"> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"><strong style="font-weight: bold; line-height: 1.75em; color: rgb(74,74,74);">contributors</strong></td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;">16</td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"><strong style="font-weight: bold; line-height: 1.75em; color: rgb(74,74,74);">作者</strong></td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;">HashiCorp(机构)</td> </tr> <tr style="border: 0; border-top: 1px solid #ccc; background-color: white;"> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"><strong style="font-weight: bold; line-height: 1.75em; color: rgb(74,74,74);">功能简介</strong></td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;">多错误管理包。可以将多个错误合并成一个标准的 error,使得多个错误管理变得更容易。</td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"></td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"></td> </tr> <tr style="border: 0; border-top: 1px solid #ccc; background-color: #F8F8F8;"> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"><strong style="font-weight: bold; line-height: 1.75em; color: rgb(74,74,74);">项目地址</strong></td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"><span class="footnote-word" style="font-weight: bold; color: rgb(60, 112, 198);">https://github.com/hashicorp/go-multierror</span><sup class="footnote-ref" style="line-height: 0; font-weight: bold; color: rgb(60, 112, 198);">[1]</sup></td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"></td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"></td> </tr> <tr style="border: 0; border-top: 1px solid #ccc; background-color: white;"> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"><strong style="font-weight: bold; line-height: 1.75em; color: rgb(74,74,74);">相关知识</strong></td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;">error 处理</td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"></td> <td style="border: 1px solid #ccc; padding: 5px 10px; text-align: left; font-size: 14px; min-width: 85px;"></td> </tr> </tbody> </table> </section><h2 data-tool="mdnice编辑器" style="padding: 0px; font-weight: bold; color: black; font-size: 22px; display: block; text-align: center; background-image: url(https://files.mdnice.com/mountain_2.png); background-position: center center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 63px; margin-top: 38px; margin-bottom: 10px;"><span class="prefix" style="display: none;"></span><span class="content" style="text-align: center; display: inline-block; height: 38px; line-height: 42px; color: rgb(60, 112, 198); background-position: left center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 63px; margin-top: 38px; font-size: 18px; margin-bottom: 10px;">一、安装</span><span class="suffix"></span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span style="background-image: url(https://files.mdnice.com/mountain_1.png); background-size: 15px 15px; display: inline-block; width: 15px; height: 15px; line-height: 15px; margin-bottom: -1px;"></span><span class="prefix" style="display: none;"></span><span class="content" style="font-size: 16px; font-weight: bold; display: inline-block; margin-left: 8px; color: rgb(60,112,198);">安装</span><span class="suffix" style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">使用 go get 进行安装</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">go</span>&nbsp;get&nbsp;github.com/hashicorp/<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">go</span>-multierror<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span style="background-image: url(https://files.mdnice.com/mountain_1.png); background-size: 15px 15px; display: inline-block; width: 15px; height: 15px; line-height: 15px; margin-bottom: -1px;"></span><span class="prefix" style="display: none;"></span><span class="content" style="font-size: 16px; font-weight: bold; display: inline-block; margin-left: 8px; color: rgb(60,112,198);">go 版本要求</span><span class="suffix" style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">该最新包需要依赖于 Go 的 1.13 或更高版本,因为 error 中的 wrap 功能是从 1.13 版本开始的。如果你当前的 go 版本低于 1.13,那么可以使用该包的 v1.0.0 tag,该版本不依赖于 1.13 中的 wrap 功能。</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">go</span>&nbsp;get&nbsp;github.com/hashicorp/<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">go</span>-multierror@v1<span class="hljs-number" style="color: #d19a66; line-height: 26px;">.0</span><span class="hljs-number" style="color: #d19a66; line-height: 26px;">.0</span><br></code></pre> <blockquote class="multiquote-1" data-tool="mdnice编辑器" style="border: none; font-size: 0.9em; overflow: auto; overflow-scrolling: touch; background: rgba(0, 0, 0, 0.05); color: #6a737d; padding-top: 10px; padding-bottom: 10px; padding-left: 20px; padding-right: 10px; margin-bottom: 20px; margin-top: 20px; padding: 15px 20px; line-height: 27px; background-color: rgb(239, 239, 239); border-left: none; display: block;"> <p style="padding-bottom: 8px; padding-top: 23px; margin: 0px; line-height: 26px; padding: 0px; font-size: 15px; color: rgb(89,89,89);">知识点:在 Go 1.13 版本之前,标准库对 error 的支持仅有 errors.New()和 fmt.Errorf()两个函数来构造 error 实例。从 1.13 版本开始,在 errors 和 fmt 标准库包中引入了新功能以简化处理包含其他错误的错误,称之为链式 error。其中就包含 errors.Unwrap()、errors.Is()和 errors.As(),以及 fmt.Errorf 中引入了%w 动词以创建 wrapError。</p> </blockquote> <h2 data-tool="mdnice编辑器" style="padding: 0px; font-weight: bold; color: black; font-size: 22px; display: block; text-align: center; background-image: url(https://files.mdnice.com/mountain_2.png); background-position: center center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 63px; margin-top: 38px; margin-bottom: 10px;"><span class="prefix" style="display: none;"></span><span class="content" style="text-align: center; display: inline-block; height: 38px; line-height: 42px; color: rgb(60, 112, 198); background-position: left center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 63px; margin-top: 38px; font-size: 18px; margin-bottom: 10px;">二、基本使用</span><span class="suffix"></span></h2> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">mutlierror 包的使用也非常简单。下面我们看下其主要的使用。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span style="background-image: url(https://files.mdnice.com/mountain_1.png); background-size: 15px 15px; display: inline-block; width: 15px; height: 15px; line-height: 15px; margin-bottom: -1px;"></span><span class="prefix" style="display: none;"></span><span class="content" style="font-size: 16px; font-weight: bold; display: inline-block; margin-left: 8px; color: rgb(60,112,198);">构建错误列表</span><span class="suffix" style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">通过 mutierror 包中的 Append 函数可以创建错误列表。该函数的行为非常类似 go 内建的 append 函数。Append 的第一个参数无论是 nil、multierror.Error 或者其他类型的 error,该函数都会返回一个 multierror.Error 类型的值,并将 Append 中第二个参数中的 err 加入到 multierror.Error 的列表中。</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">var</span>&nbsp;result&nbsp;error<br><br><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;err&nbsp;:=&nbsp;step1();&nbsp;err&nbsp;!=&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span>&nbsp;{<br>&nbsp;result&nbsp;=&nbsp;multierror.Append(result,&nbsp;err)<br>}<br><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;err&nbsp;:=&nbsp;step2();&nbsp;err&nbsp;!=&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span>&nbsp;{<br>&nbsp;result&nbsp;=&nbsp;multierror.Append(result,&nbsp;err)<br>}<br><br><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span>&nbsp;result<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span style="background-image: url(https://files.mdnice.com/mountain_1.png); background-size: 15px 15px; display: inline-block; width: 15px; height: 15px; line-height: 15px; margin-bottom: -1px;"></span><span class="prefix" style="display: none;"></span><span class="content" style="font-size: 16px; font-weight: bold; display: inline-block; margin-left: 8px; color: rgb(60,112,198);">自定义格式化输出</span><span class="suffix" style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">通过指定 multierror.Error 的实例变量中的 ErrorFormat 属性,就可以自定义 Error() string 的输出格式:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">var</span>&nbsp;result&nbsp;*multierror.Error<br><br><span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//&nbsp;...&nbsp;accumulate&nbsp;errors&nbsp;here,&nbsp;maybe&nbsp;using&nbsp;Append</span><br><br><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;result&nbsp;!=&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span>&nbsp;{<br>&nbsp;result.ErrorFormat&nbsp;=&nbsp;<span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">func</span><span class="hljs-params" style="line-height: 26px;">([]error)</span>&nbsp;<span class="hljs-title" style="color: #61aeee; line-height: 26px;">string</span></span>&nbsp;{<br>&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">"errors!"</span><br>&nbsp;}<br>}<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span style="background-image: url(https://files.mdnice.com/mountain_1.png); background-size: 15px 15px; display: inline-block; width: 15px; height: 15px; line-height: 15px; margin-bottom: -1px;"></span><span class="prefix" style="display: none;"></span><span class="content" style="font-size: 16px; font-weight: bold; display: inline-block; margin-left: 8px; color: rgb(60,112,198);">访问错误列表</span><span class="suffix" style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">multierror.Error 实现了 error 接口,所以即使调用者不知道返回的错误类型是否是 multierror,该错误依然能正常工作。同时,我们也可以通过类型断言的方式来校验返回的错误是否是 multierror.Error 类型,以便可以访问 multierror.Error 中的所有 error。</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;err&nbsp;:=&nbsp;something();&nbsp;err&nbsp;!=&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span>&nbsp;{<br>&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;merr,&nbsp;ok&nbsp;:=&nbsp;err.(*multierror.Error);&nbsp;ok&nbsp;{<br>&nbsp;&nbsp;<span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//&nbsp;Use&nbsp;merr.Errors</span><br>&nbsp;}<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">当然,也可以使用 go 内建包 errors.Unwrap()函数对 mutlierror.Errors 依次解析,直到所有的 error 都被解析完成。</p> <blockquote class="multiquote-1" data-tool="mdnice编辑器" style="border: none; font-size: 0.9em; overflow: auto; overflow-scrolling: touch; background: rgba(0, 0, 0, 0.05); color: #6a737d; padding-top: 10px; padding-bottom: 10px; padding-left: 20px; padding-right: 10px; margin-bottom: 20px; margin-top: 20px; padding: 15px 20px; line-height: 27px; background-color: rgb(239, 239, 239); border-left: none; display: block;"> <p style="padding-bottom: 8px; padding-top: 23px; margin: 0px; line-height: 26px; padding: 0px; font-size: 15px; color: rgb(89,89,89);">知识点:内建包中的 errors.Unwrap()函数,可以对 error 层层拆解。对于自定义的 error 类型,不仅要实现 Error()函数,同时也需要实现 Unwrap 函数。</p> </blockquote> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">errors.Unwrap()函数的源代码如下:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">func</span>&nbsp;<span class="hljs-title" style="color: #61aeee; line-height: 26px;">Unwrap</span><span class="hljs-params" style="line-height: 26px;">(err&nbsp;error)</span>&nbsp;<span class="hljs-title" style="color: #61aeee; line-height: 26px;">error</span></span>&nbsp;{<br>&gt;&nbsp;u,&nbsp;ok&nbsp;:=&nbsp;err.(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">interface</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Unwrap()&nbsp;error<br>&nbsp;&nbsp;&nbsp;&nbsp;})<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;!ok&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span>&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span><br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span>&nbsp;u.Unwrap()<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">如果参数 err 没有实现 Unwrap()函数,则说明是基础 error,直接返回 nil,否则调用元 err 实现的 Unwrap()函数并返回。</p> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span style="background-image: url(https://files.mdnice.com/mountain_1.png); background-size: 15px 15px; display: inline-block; width: 15px; height: 15px; line-height: 15px; margin-bottom: -1px;"></span><span class="prefix" style="display: none;"></span><span class="content" style="font-size: 16px; font-weight: bold; display: inline-block; margin-left: 8px; color: rgb(60,112,198);">提取特定的 error 值</span><span class="suffix" style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">标准库中的 errors.As 函数可以直接从 multierror.Error 中提取一个特定的 error:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//&nbsp;Assume&nbsp;err&nbsp;is&nbsp;a&nbsp;multierror&nbsp;value</span><br>err&nbsp;:=&nbsp;somefunc()<br><br><span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//&nbsp;We&nbsp;want&nbsp;to&nbsp;know&nbsp;if&nbsp;"err"&nbsp;has&nbsp;a&nbsp;"RichErrorType"&nbsp;in&nbsp;it&nbsp;and&nbsp;extract&nbsp;it.</span><br><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">var</span>&nbsp;errRich&nbsp;RichErrorType<br><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;errors.As(err,&nbsp;&amp;errRich)&nbsp;{<br>&nbsp;<span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//&nbsp;It&nbsp;has&nbsp;it,&nbsp;and&nbsp;now&nbsp;errRich&nbsp;is&nbsp;populated.</span><br>}<br></code></pre> <blockquote class="multiquote-1" data-tool="mdnice编辑器" style="border: none; font-size: 0.9em; overflow: auto; overflow-scrolling: touch; background: rgba(0, 0, 0, 0.05); color: #6a737d; padding-top: 10px; padding-bottom: 10px; padding-left: 20px; padding-right: 10px; margin-bottom: 20px; margin-top: 20px; padding: 15px 20px; line-height: 27px; background-color: rgb(239, 239, 239); border-left: none; display: block;"> <p style="padding-bottom: 8px; padding-top: 23px; margin: 0px; line-height: 26px; padding: 0px; font-size: 15px; color: rgb(89,89,89);">知识点:标准库中的 errors.As 函数会调用 Unwrap 函数,将 err 层层拆解,如果拆解到的 error 和目标 error 类型相同,则将该 error 赋值给目标参数 errRich。</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span style="background-image: url(https://files.mdnice.com/mountain_1.png); background-size: 15px 15px; display: inline-block; width: 15px; height: 15px; line-height: 15px; margin-bottom: -1px;"></span><span class="prefix" style="display: none;"></span><span class="content" style="font-size: 16px; font-weight: bold; display: inline-block; margin-left: 8px; color: rgb(60,112,198);">检查 multierror.Error 中是否有具体的错误值</span><span class="suffix" style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">有时候一些函数会返回具体的错误值,比如 os 包中返回的 ErrNotExists。所以,我们就可以通过 errors.Is 函数来检查 multierror.Error 中是否存在具体的错误值。</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//&nbsp;Assume&nbsp;err&nbsp;is&nbsp;a&nbsp;multierror&nbsp;value</span><br>err&nbsp;:=&nbsp;somefunc()<br><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;errors.Is(err,&nbsp;os.ErrNotExist)&nbsp;{<br>&nbsp;<span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//&nbsp;err&nbsp;contains&nbsp;os.ErrNotExist</span><br>}<br></code></pre> <blockquote class="multiquote-1" data-tool="mdnice编辑器" style="border: none; font-size: 0.9em; overflow: auto; overflow-scrolling: touch; background: rgba(0, 0, 0, 0.05); color: #6a737d; padding-top: 10px; padding-bottom: 10px; padding-left: 20px; padding-right: 10px; margin-bottom: 20px; margin-top: 20px; padding: 15px 20px; line-height: 27px; background-color: rgb(239, 239, 239); border-left: none; display: block;"> <p style="padding-bottom: 8px; padding-top: 23px; margin: 0px; line-height: 26px; padding: 0px; font-size: 15px; color: rgb(89,89,89);">知识点:errors.Is 用来判断链式 err 中是否有具体的 error 值(通常称之为哨兵 error)</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span style="background-image: url(https://files.mdnice.com/mountain_1.png); background-size: 15px 15px; display: inline-block; width: 15px; height: 15px; line-height: 15px; margin-bottom: -1px;"></span><span class="prefix" style="display: none;"></span><span class="content" style="font-size: 16px; font-weight: bold; display: inline-block; margin-left: 8px; color: rgb(60,112,198);">错误处理</span><span class="suffix" style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">在实际使用中,错误都是由从函数中创建并返回的。调用者用 if 语句判断返回的错误是否为 nil(error 飞初始化的值)来判断错误是否存在。那么,在 multierror.Error 类型中,何时返回 nil,何时返回错误呢? 在 multierror.Error 的实例中,可以通过该类型的 ErrorOrNil 方法来返回错误或 nil。该函数内部实现中判断该实例中的 Errors 切片是否为空,如果不为空,则返回该实例,否则返回 nil。</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">var</span>&nbsp;result&nbsp;*multierror.Error<br><br><span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//&nbsp;...&nbsp;accumulate&nbsp;errors&nbsp;here</span><br><br><span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//&nbsp;Return&nbsp;the&nbsp;`error`&nbsp;only&nbsp;if&nbsp;errors&nbsp;were&nbsp;added&nbsp;to&nbsp;the&nbsp;multierror,&nbsp;otherwise</span><br><span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//&nbsp;return&nbsp;nil&nbsp;since&nbsp;there&nbsp;are&nbsp;no&nbsp;errors.</span><br><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span>&nbsp;result.ErrorOrNil()<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">ErrorOrNil 函数的实现如下:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">func</span>&nbsp;<span class="hljs-params" style="line-height: 26px;">(e&nbsp;*Error)</span>&nbsp;<span class="hljs-title" style="color: #61aeee; line-height: 26px;">ErrorOrNil</span><span class="hljs-params" style="line-height: 26px;">()</span>&nbsp;<span class="hljs-title" style="color: #61aeee; line-height: 26px;">error</span></span>&nbsp;{<br>&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;e&nbsp;==&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span>&nbsp;{<br>&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span>&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span><br>&nbsp;}<br>&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;<span class="hljs-built_in" style="color: #e6c07b; line-height: 26px;">len</span>(e.Errors)&nbsp;==&nbsp;<span class="hljs-number" style="color: #d19a66; line-height: 26px;">0</span>&nbsp;{<br>&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span>&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span><br>&nbsp;}<br><br>&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span>&nbsp;e<br>}<br></code></pre> <blockquote class="multiquote-1" data-tool="mdnice编辑器" style="border: none; font-size: 0.9em; overflow: auto; overflow-scrolling: touch; background: rgba(0, 0, 0, 0.05); color: #6a737d; padding-top: 10px; padding-bottom: 10px; padding-left: 20px; padding-right: 10px; margin-bottom: 20px; margin-top: 20px; padding: 15px 20px; line-height: 27px; background-color: rgb(239, 239, 239); border-left: none; display: block;"> <p style="padding-bottom: 8px; padding-top: 23px; margin: 0px; line-height: 26px; padding: 0px; font-size: 15px; color: rgb(89,89,89);">知识点:在 Go 中错误一般是从函数中创建并作为值返回的。调用者需要使用 if 语句判断返回的错误是否为 nil 来判断错误是否存在。 同时,在 Go 中,函数有多个返回值时,错误一般放到最后。</p> </blockquote> <h2 data-tool="mdnice编辑器" style="padding: 0px; font-weight: bold; color: black; font-size: 22px; display: block; text-align: center; background-image: url(https://files.mdnice.com/mountain_2.png); background-position: center center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 63px; margin-top: 38px; margin-bottom: 10px;"><span class="prefix" style="display: none;"></span><span class="content" style="text-align: center; display: inline-block; height: 38px; line-height: 42px; color: rgb(60, 112, 198); background-position: left center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 63px; margin-top: 38px; font-size: 18px; margin-bottom: 10px;">三、实现原理分析</span><span class="suffix"></span></h2> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span style="background-image: url(https://files.mdnice.com/mountain_1.png); background-size: 15px 15px; display: inline-block; width: 15px; height: 15px; line-height: 15px; margin-bottom: -1px;"></span><span class="prefix" style="display: none;"></span><span class="content" style="font-size: 16px; font-weight: bold; display: inline-block; margin-left: 8px; color: rgb(60,112,198);">multierror.Error 类型的定义</span><span class="suffix" style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">multierror.Error 类型的结构很简单,因为要实现多错误管理,所以有一个 error 类型的切片;另外还有一个 ErrorformatFunc 函数类型,用于格式化输出 Error 的描述。如下:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">type</span>&nbsp;Error&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">struct</span>&nbsp;{<br>&nbsp;Errors&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[]error<br>&nbsp;ErrorFormat&nbsp;ErrorFormatFunc<br>}<br><br><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">type</span>&nbsp;ErrorFormatFunc&nbsp;<span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">func</span><span class="hljs-params" style="line-height: 26px;">([]error)</span>&nbsp;<span class="hljs-title" style="color: #61aeee; line-height: 26px;">string</span></span><br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">这里我们需要提及到 golang 中的 error 类型的知识点。</p> <blockquote class="multiquote-1" data-tool="mdnice编辑器" style="border: none; font-size: 0.9em; overflow: auto; overflow-scrolling: touch; background: rgba(0, 0, 0, 0.05); color: #6a737d; padding-top: 10px; padding-bottom: 10px; padding-left: 20px; padding-right: 10px; margin-bottom: 20px; margin-top: 20px; padding: 15px 20px; line-height: 27px; background-color: rgb(239, 239, 239); border-left: none; display: block;"> <p style="padding-bottom: 8px; padding-top: 23px; margin: 0px; line-height: 26px; padding: 0px; font-size: 15px; color: rgb(89,89,89);">知识点:Golang 中的 error 实质上就是一个简单的接口类型。只要实现了这个接口,就可以将其视为一种 error。</p> </blockquote> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">type</span>&nbsp;error&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">interface</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;Error()&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">string</span><br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">所以,multierror.Error 类型也实现了 Error()方法:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><br><span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">func</span>&nbsp;<span class="hljs-params" style="line-height: 26px;">(e&nbsp;*Error)</span>&nbsp;<span class="hljs-title" style="color: #61aeee; line-height: 26px;">Error</span><span class="hljs-params" style="line-height: 26px;">()</span>&nbsp;<span class="hljs-title" style="color: #61aeee; line-height: 26px;">string</span></span>&nbsp;{<br>&nbsp;fn&nbsp;:=&nbsp;e.ErrorFormat<br>&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;fn&nbsp;==&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span>&nbsp;{<br>&nbsp;&nbsp;fn&nbsp;=&nbsp;ListFormatFunc<br>&nbsp;}<br><br>&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span>&nbsp;fn(e.Errors)<br>}<br></code></pre> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">multierror.Error 类型实现了 error 接口,那么该类型的变量就可以存储到 error 接口的变量中。</p> <blockquote class="multiquote-1" data-tool="mdnice编辑器" style="border: none; font-size: 0.9em; overflow: auto; overflow-scrolling: touch; background: rgba(0, 0, 0, 0.05); color: #6a737d; padding-top: 10px; padding-bottom: 10px; padding-left: 20px; padding-right: 10px; margin-bottom: 20px; margin-top: 20px; padding: 15px 20px; line-height: 27px; background-color: rgb(239, 239, 239); border-left: none; display: block;"> <p style="padding-bottom: 8px; padding-top: 23px; margin: 0px; line-height: 26px; padding: 0px; font-size: 15px; color: rgb(89,89,89);">知识点:任何类型只要实现了 interface 类型的所有方法,就可以声称该类型实现了这个接口,该类型的变量就可以存储到 interface 变量中。</p> </blockquote> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span style="background-image: url(https://files.mdnice.com/mountain_1.png); background-size: 15px 15px; display: inline-block; width: 15px; height: 15px; line-height: 15px; margin-bottom: -1px;"></span><span class="prefix" style="display: none;"></span><span class="content" style="font-size: 16px; font-weight: bold; display: inline-block; margin-left: 8px; color: rgb(60,112,198);">multierror.Append 函数的实现</span><span class="suffix" style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">在基本使用一节我们提到,可以通过 Append 函数来构建一个具体的多错误值实例 multierror.Error。这个本质上是将 error 值键入到 multierror.Error 类型的 Errors 切片中。</p> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">同时,我们提到,该 Append 函数无论是我们看下是如何实现:</p> <ul data-tool="mdnice编辑器" style="margin-top: 8px; margin-bottom: 8px; padding-left: 25px; color: black; list-style-type: disc;"> <li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;">首先通过类型断言 err.(type)来判断 err 的类型</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;">如果参数中的 err 不是 multierror.Error 类型,则新构建一个 errors 切片,将 err 和 errs 都加入到切片中,然后再构建一个空 multierrors.Error 类型的实例,然后再递归调用 multierrors.Append 函数。</section></li><li><section style="margin-top: 5px; margin-bottom: 5px; line-height: 26px; text-align: left; color: rgb(1,1,1); font-weight: 500;">如果参数中的 err 的类型就是 Error,那么就将 errs 错误加入到 Error 结构类型中的 Errors 切片中。</section></li></ul> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">具体实现如下:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">func</span>&nbsp;<span class="hljs-title" style="color: #61aeee; line-height: 26px;">Append</span><span class="hljs-params" style="line-height: 26px;">(err&nbsp;error,&nbsp;errs&nbsp;...error)</span>&nbsp;*<span class="hljs-title" style="color: #61aeee; line-height: 26px;">Error</span></span>&nbsp;{<br>&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">switch</span>&nbsp;err&nbsp;:=&nbsp;err.(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">type</span>)&nbsp;{<br>&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">case</span>&nbsp;*Error:<br>&nbsp;&nbsp;<span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//&nbsp;Typed&nbsp;nils&nbsp;can&nbsp;reach&nbsp;here,&nbsp;so&nbsp;initialize&nbsp;if&nbsp;we&nbsp;are&nbsp;nil</span><br>&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;err&nbsp;==&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;err&nbsp;=&nbsp;<span class="hljs-built_in" style="color: #e6c07b; line-height: 26px;">new</span>(Error)<br>&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;<span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//&nbsp;Go&nbsp;through&nbsp;each&nbsp;error&nbsp;and&nbsp;flatten</span><br>&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">for</span>&nbsp;_,&nbsp;e&nbsp;:=&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">range</span>&nbsp;errs&nbsp;{<br>&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">switch</span>&nbsp;e&nbsp;:=&nbsp;e.(<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">type</span>)&nbsp;{<br>&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">case</span>&nbsp;*Error:<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;e&nbsp;!=&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;err.Errors&nbsp;=&nbsp;<span class="hljs-built_in" style="color: #e6c07b; line-height: 26px;">append</span>(err.Errors,&nbsp;e.Errors...)<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">default</span>:<br>&nbsp;&nbsp;&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;e&nbsp;!=&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;err.Errors&nbsp;=&nbsp;<span class="hljs-built_in" style="color: #e6c07b; line-height: 26px;">append</span>(err.Errors,&nbsp;e)<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span>&nbsp;err<br>&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">default</span>:<br>&nbsp;&nbsp;newErrs&nbsp;:=&nbsp;<span class="hljs-built_in" style="color: #e6c07b; line-height: 26px;">make</span>([]error,&nbsp;<span class="hljs-number" style="color: #d19a66; line-height: 26px;">0</span>,&nbsp;<span class="hljs-built_in" style="color: #e6c07b; line-height: 26px;">len</span>(errs)+<span class="hljs-number" style="color: #d19a66; line-height: 26px;">1</span>)<br>&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;err&nbsp;!=&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span>&nbsp;{<br>&nbsp;&nbsp;&nbsp;newErrs&nbsp;=&nbsp;<span class="hljs-built_in" style="color: #e6c07b; line-height: 26px;">append</span>(newErrs,&nbsp;err)<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;newErrs&nbsp;=&nbsp;<span class="hljs-built_in" style="color: #e6c07b; line-height: 26px;">append</span>(newErrs,&nbsp;errs...)<br><br>&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span>&nbsp;Append(&amp;Error{},&nbsp;newErrs...)<br>&nbsp;}<br>}<br></code></pre> <h3 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span style="background-image: url(https://files.mdnice.com/mountain_1.png); background-size: 15px 15px; display: inline-block; width: 15px; height: 15px; line-height: 15px; margin-bottom: -1px;"></span><span class="prefix" style="display: none;"></span><span class="content" style="font-size: 16px; font-weight: bold; display: inline-block; margin-left: 8px; color: rgb(60,112,198);">自定义格式化错误输出实现</span><span class="suffix" style="display: none;"></span></h3> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">在基本使用中提到,可以给 multierrors.Error 类型中的 ErrorFormat 属性赋值一个输出错误的函数,这样就能按自定义函数的格式将错误列表输出了。该输出的实现实际是在 Error 函数中定义的:</p> <pre class="custom" data-tool="mdnice编辑器" style="margin-top: 10px; margin-bottom: 10px; border-radius: 5px; box-shadow: rgba(0, 0, 0, 0.55) 0px 2px 10px;"><span style="display: block; background: url(https://files.mdnice.com/user/3441/876cad08-0422-409d-bb5a-08afec5da8ee.svg); height: 30px; width: 100%; background-size: 40px; background-repeat: no-repeat; background-color: #282c34; margin-bottom: -7px; border-radius: 5px; background-position: 10px 10px;"></span><code class="hljs" style="overflow-x: auto; padding: 16px; color: #abb2bf; display: -webkit-box; font-family: Operator Mono, Consolas, Monaco, Menlo, monospace; font-size: 12px; -webkit-overflow-scrolling: touch; padding-top: 15px; background: #282c34; border-radius: 5px;"><span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">func</span>&nbsp;<span class="hljs-params" style="line-height: 26px;">(e&nbsp;*Error)</span>&nbsp;<span class="hljs-title" style="color: #61aeee; line-height: 26px;">Error</span><span class="hljs-params" style="line-height: 26px;">()</span>&nbsp;<span class="hljs-title" style="color: #61aeee; line-height: 26px;">string</span></span>&nbsp;{<br>&nbsp;fn&nbsp;:=&nbsp;e.ErrorFormat<br>&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;fn&nbsp;==&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span>&nbsp;{<br>&nbsp;&nbsp;fn&nbsp;=&nbsp;ListFormatFunc<br>&nbsp;}<br><br>&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span>&nbsp;fn(e.Errors)<br>}<br><br><br><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">var</span>&nbsp;result&nbsp;*multierror.Error<br><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">if</span>&nbsp;result&nbsp;!=&nbsp;<span class="hljs-literal" style="color: #56b6c2; line-height: 26px;">nil</span>&nbsp;{<br>&nbsp;result.ErrorFormat&nbsp;=&nbsp;<span class="hljs-function" style="line-height: 26px;"><span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">func</span><span class="hljs-params" style="line-height: 26px;">([]error)</span>&nbsp;<span class="hljs-title" style="color: #61aeee; line-height: 26px;">string</span></span>&nbsp;{<br>&nbsp;&nbsp;<span class="hljs-keyword" style="color: #c678dd; line-height: 26px;">return</span>&nbsp;<span class="hljs-string" style="color: #98c379; line-height: 26px;">"errors!"</span><br>&nbsp;}<br>}<br><br>result.Error()&nbsp;<span class="hljs-comment" style="color: #5c6370; font-style: italic; line-height: 26px;">//就会按照ErrorFormat函数输出错误</span><br><br></code></pre> <h2 data-tool="mdnice编辑器" style="padding: 0px; font-weight: bold; color: black; font-size: 22px; display: block; text-align: center; background-image: url(https://files.mdnice.com/mountain_2.png); background-position: center center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 63px; margin-top: 38px; margin-bottom: 10px;"><span class="prefix" style="display: none;"></span><span class="content" style="text-align: center; display: inline-block; height: 38px; line-height: 42px; color: rgb(60, 112, 198); background-position: left center; background-repeat: no-repeat; background-attachment: initial; background-origin: initial; background-clip: initial; background-size: 63px; margin-top: 38px; font-size: 18px; margin-bottom: 10px;">应用场景</span><span class="suffix"></span></h2> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">多错误管理的应用场景一般是用在一个函数的逻辑中需要把所有的错误都返回的情况。比如在服务启动时,对 redis、kafka、mysql 等各种资源初始化场景,可以把所有相关资源初始化的错误都返回。还有一种场景就是在 web 请求中,校验请求参数时,返回所有参数的校验错误给客户端的场景。</p> <h5 data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 16px;"><span class="prefix" style="display: none;"></span><span class="content">---特别推荐---</span><span class="suffix" style="display: none;"></span></h5> <p data-tool="mdnice编辑器" style="font-size: 16px; padding-bottom: 8px; margin: 0; padding-top: 23px; color: rgb(74,74,74); line-height: 1.75em;">特别推荐:一个专注go项目实战、项目中踩坑经验及避坑指南、各种好玩的go工具的公众号。「Go学堂」,专注实用性,非常值得大家关注。点击下方公众号卡片,直接关注。关注送《100个go常见的错误》pdf文档。</p> <h3 class="footnotes-sep" data-tool="mdnice编辑器" style="margin-top: 30px; margin-bottom: 15px; padding: 0px; font-weight: bold; color: black; font-size: 20px;"><span style="line-height: 15px; margin-bottom: -1px; background-image: none; background-size: none; display: block; width: auto; height: auto;">参考资料</span></h3> <section class="footnotes" data-tool="mdnice编辑器" style="padding-top: 8px;"> <span id="fn1" class="footnote-item" style="display: flex;"><span class="footnote-num" style="display: inline; width: 10%; background: none; font-size: 80%; opacity: 0.6; line-height: 26px; font-family: ptima-Regular, Optima, PingFangSC-light, PingFangTC-light, 'PingFang SC', Cambria, Cochin, Georgia, Times, 'Times New Roman', serif; color: rgb(60, 112, 198);">[1] </span><p style="padding-bottom: 8px; padding-top: 23px; display: inline; font-size: 14px; width: 90%; padding: 0px; margin: 0; line-height: 26px; word-break: break-all; width: calc(100%-50); color: rgb(60, 112, 198); font-weight: bold;">https://github.com/hashicorp/go-multierror: <em style="color: rgb(60, 112, 198); font-style: normal; border-bottom-color: 1px dashed rgb(60, 112, 198); font-size: 14px; font-weight: normal; border-bottom: 1px dashed rgb(60, 112, 198);">https://github.com/hashicorp/go-multierror</em></p> </span> </section> </section>

有疑问加站长微信联系(非本文作者))

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

6129 次点击  ∙  2 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传