List of Error - text.Baldanders.info
tag:text.Baldanders.info,2023-06-26:/tags
2023-06-26T21:22:20+09:00
帰ってきた「しっぽのさきっちょ」
https://text.baldanders.info/images/avatar.jpg
https://text.baldanders.info/images/avatar.jpg
goark/errs パッケージ v1.3.2 をリリースした
tag:text.Baldanders.info,2023-06-26:/release/2023/06/errs-package-v1_3_2-is-released/
2023-06-26T12:22:20+00:00
2023-06-26T23:10:38+00:00
concurrency-safe なマルチエラー型を作った。
Spiegel
https://baldanders.info/profile/
<p><a href="https://text.baldanders.info/remark/2023/06/benchmark-for-errs-package/" title="拙作 gorak/errs パッケージの性能評価をしてもらった">この前書いた記事</a>で,最後の方に「そうそう <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a><code>.Join</code> 互換の関数ってあったほうがいいのかなぁ」と漠然と書いたのだが,その後,複数の goroutine を跨いでエラーハンドリングを行う必要ができたので, concurrency-safe なマルチエラー型 <a href="https://github.com/goark/errs" title="goark/errs: Error handling for Golang"><code>errs</code></a><code>.Errors</code> を作ってリリースした。</p>
<ul>
<li><a href="https://github.com/goark/errs/releases/tag/v1.3.2">Release v1.3.2 · goark/errs · GitHub</a></li>
</ul>
<p>いやぁ,並行処理書くの久しぶりで,色々とバグを潰してたら v1.3.2 まで上がってしまった(笑)</p>
<p>たとえば,こんな感じに使える。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"sync"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/goark/errs"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">generateMultiError</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">errlist</span> <span class="o">:=</span> <span class="o">&</span><span class="nx">errs</span><span class="p">.</span><span class="nx">Errors</span><span class="p">{}</span>
</span></span><span class="line"><span class="cl"> <span class="kd">var</span> <span class="nx">wg</span> <span class="nx">sync</span><span class="p">.</span><span class="nx">WaitGroup</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">i</span> <span class="o">:=</span> <span class="mi">1</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><=</span> <span class="mi">2</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">i</span> <span class="o">:=</span> <span class="nx">i</span>
</span></span><span class="line"><span class="cl"> <span class="nx">wg</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">go</span> <span class="kd">func</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">defer</span> <span class="nx">wg</span><span class="p">.</span><span class="nf">Done</span><span class="p">()</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">errlist</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Errorf</span><span class="p">(</span><span class="s">"error %d"</span><span class="p">,</span> <span class="nx">i</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="p">}()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">wg</span><span class="p">.</span><span class="nf">Wait</span><span class="p">()</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">return</span> <span class="nx">errlist</span><span class="p">.</span><span class="nf">ErrorOrNil</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">generateMultiError</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"%+v\n"</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span> <span class="c1">// {"Type":"*errs.Errors","Errs":[{"Type":"*errors.errorString","Msg":"error 2"},{"Type":"*errors.errorString","Msg":"error 1"}]}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>また <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a><code>.Join()</code> 互換の関数も用意してみた。
こんな感じ。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"errors"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"io"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"os"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/goark/errs"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">generateMultiError</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">return</span> <span class="nx">errs</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">ErrInvalid</span><span class="p">,</span> <span class="nx">io</span><span class="p">.</span><span class="nx">EOF</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">generateMultiError</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"%+v\n"</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span> <span class="c1">// {"Type":"*errs.Errors","Errs":[{"Type":"*errors.errorString","Msg":"invalid argument"},{"Type":"*errors.errorString","Msg":"EOF"}]}
</span></span></span><span class="line"><span class="cl"><span class="c1"></span> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">errors</span><span class="p">.</span><span class="nf">Is</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">io</span><span class="p">.</span><span class="nx">EOF</span><span class="p">))</span> <span class="c1">// true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>今回新たに作った <a href="https://github.com/goark/errs" title="goark/errs: Error handling for Golang"><code>errs</code></a><code>.Errors</code> 型は <code>Unwrap() []error</code> メソッドを持っているため, <a href="https://go.dev/">Go</a> 1.20 以降であれば <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a><code>.Is()</code> および <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a><code>.As()</code> 関数を使って評価することができる。</p>
<p>これで <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a> 標準パッケージと互換性ありと言えるようになったかな?</p>
<h2>ブックマーク</h2>
<ul>
<li>
<p><a href="https://tech.kanmu.co.jp/entry/2023/06/19/150000">次なる<code>pkg/errors</code>を探して - カンムテックブログ</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/golang/wrapping-multiple-errors/">【Go 1.20 の予習】複数 error を返す Unwrap メソッドについて</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/release/errs-package-for-golang/">Go 言語用エラーハンドリング・パッケージ</a></p>
</li>
<li>
<p><a href="https://zenn.dev/spiegel/books/error-handling-in-golang">Go のエラーハンドリング</a> : Zenn 本書きました</p>
</li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51pUKQajnaL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4873118468?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">Go言語による並行処理</a></dt>
<dd>Katherine Cox-Buday (著), 山口 能迪 (翻訳)</dd>
<dd>オライリージャパン 2018-10-26</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4873118468 (ASIN), 9784873118468 (EAN), 4873118468 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.oreilly.co.jp/books/9784873118468/">Eブック版もある</a>。感想は<a href="https://text.baldanders.info/remark/2018/11/concurrency-in-go/">こちら</a>。 Go 言語で並行処理を書くならこの本は必読書になるだろう。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2020-01-13">2020-01-13</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Go言語による並行処理 -->
拙作 gorak/errs パッケージの性能評価をしてもらった
tag:text.Baldanders.info,2023-06-24:/remark/2023/06/benchmark-for-errs-package/
2023-06-24T01:06:56+00:00
2023-06-24T14:13:39+00:00
ありがとうございます 🙇
Spiegel
https://baldanders.info/profile/
<p>こんなマイナーなパッケージの性能評価をしていただいてありがとうございます <abbr class="emoji-chars" title="ペコン">🙇</abbr> いや,マジで。</p>
<ul>
<li><a href="https://tech.kanmu.co.jp/entry/2023/06/19/150000">次なる<code>pkg/errors</code>を探して - カンムテックブログ</a></li>
<li><a href="https://orisano.hatenablog.com/entry/2023/06/21/231349">次なる pkg/errors を探してを読んで - 薄いブログ</a></li>
</ul>
<p><a href="https://github.com/pkg/errors" title="pkg/errors: Simple error handling primitives"><code>pkg/errors</code></a> は昔から人気の高いエラーハンドリング・パッケージで,私も随分お世話になった。
このパッケージの更新が止まって read-only になったのに伴い代替となるパッケージが望まれていたのは知っている。
で,登場したのが <a href="https://github.com/cockroachdb/errors" title="cockroachdb/errors: Go error library with error portability over the network"><code>cockroachdb/errors</code></a> パッケージなわけだ。</p>
<p><a href="https://github.com/cockroachdb/errors" title="cockroachdb/errors: Go error library with error portability over the network"><code>cockroachdb/errors</code></a> パッケージは,おそらく CockroachDB などのデータベース操作に向いたエラーハンドリング・パッケージと思われ, <a href="https://github.com/pkg/errors" title="pkg/errors: Simple error handling primitives"><code>pkg/errors</code></a> との互換性を維持したまま PII (Personally Identifiable Information) のマスキングもできる優れものである。
<a href="https://github.com/pkg/errors" title="pkg/errors: Simple error handling primitives"><code>pkg/errors</code></a> からの乗り換えを考えるなら <a href="https://github.com/cockroachdb/errors" title="cockroachdb/errors: Go error library with error portability over the network"><code>cockroachdb/errors</code></a> パッケージはアリな選択だと思うし個人的にもお勧めである。</p>
<p>一方で拙作の <a href="https://github.com/goark/errs" title="goark/errs: Error handling for Golang"><code>goark/errs</code></a> はもう少し違うところを目指していて</p>
<ul>
<li>任意の <code>error</code> インスタンスをラッピングすることに主眼を置く
<ul>
<li>任意の error インスタンスを原因エラーとして埋め込み可能</li>
</ul>
</li>
<li>任意のコンテキスト情報を埋め込み可能
<ul>
<li>既定でエラーが発生した関数名をコンテキスト情報として保持する</li>
</ul>
</li>
<li>構造化されたエラー情報を JSON 形式で出力可能
<ul>
<li>MarshalJSON() メソッド完備</li>
<li>書式 <code>%+v</code> を使って JSON 形式で出力</li>
<li>任意の <code>error</code> インスタンスで(<code>Unwrap</code> メソッドの挙動に従い)可能な限り構造を辿って出力</li>
</ul>
</li>
</ul>
<p>といった機能を有している。
もちろんこれは <a href="https://github.com/pkg/errors" title="pkg/errors: Simple error handling primitives"><code>pkg/errors</code></a> パッケージに対するささやかな不満から来ている。</p>
<p>私は<a href="https://zenn.dev/spiegel/books/error-handling-in-golang/viewer/error-logging" title="ぼくがかんがえたさいきょうのえらーろぐ|Go のエラーハンドリング">「スタック情報は9割以上がノイズ」「藁束の中から金の針を探すようなもの」</a>という危険思想の持ち主なので,どういう形であれスタック情報を丸ごとどーんと出力することはしないようにしている。
他人様が書いた Java コードのデバッグでカジュアルにスタックトレースを吐き出しやがる(しかもそれを見ても結局分からずデバッガを動かす羽目になる)のに辟易してたというのもある。</p>
<p>それならスタック情報はエラーを吐き出した関数名を保持するのみとし,あとはエラーに至る「文脈(context)」をできる限りかき集めてエラー・インスタンスに突っ込むという戦略のほうが幾らかマシだろう,と考えたのだ。
どうしても関数呼び出しの構造が欲しければ,エラーを検出した時点で都度ラッピングしていけばいいという考え方である。</p>
<p>ところで最初に挙げた記事では</p>
<figure>
<blockquote>出力の処理は <code>json.Marshal</code> と <code>fmt.Sprintf</code> を使っています。 json.Marshal を高速化するために <a href="https://github.com/goccy/go-json"><code>goccy/go-json</code></a> に変えるのもありかもしれません。</blockquote>
<figcaption><div><q><a href="https://orisano.hatenablog.com/entry/2023/06/21/231349">次なる pkg/errors を探してを読んで</a></q>より</div></figcaption>
</figure>
<p>と評価をいただいていて, JSON の marshalling については(一瞬心が揺らいだが)性能がよくてもサードパーティのパッケージには依存したくないというのがあるので,パスさせていただくが, <a href="https://pkg.go.dev/fmt" title="fmt package - fmt - Go Packages"><code>fmt</code></a><code>.Sprintf</code> に関しては正直に言って実装をサボっているだけなので,少し改善してみることにした。</p>
<p>まずは <a href="https://github.com/miyataka/benchmark_pkg_errors_alternatives">miyataka/benchmark_pkg_errors_alternatives</a> を拝借して改めてベンチマークをとってみる。
他のパッケージと比べても仕方がないので <a href="https://github.com/goark/errs" title="goark/errs: Error handling for Golang"><code>goark/errs</code></a> を使った結果のみ示すと</p>
<table>
<thead>
<tr>
<th>benchmark</th>
<th style="text-align:right">ns/op</th>
<th style="text-align:right">B/op</th>
<th style="text-align:right">allocs/op</th>
</tr>
</thead>
<tbody>
<tr>
<td>BenchmarkErrors/goark/errs-stack-10-12</td>
<td style="text-align:right">2746</td>
<td style="text-align:right">648</td>
<td style="text-align:right">7</td>
</tr>
<tr>
<td>BenchmarkErrors/goark/errs-stack-100-12</td>
<td style="text-align:right">3278</td>
<td style="text-align:right">648</td>
<td style="text-align:right">7</td>
</tr>
<tr>
<td>BenchmarkErrors/goark/errs-stack-1000-12</td>
<td style="text-align:right">6810</td>
<td style="text-align:right">648</td>
<td style="text-align:right">7</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%s-stack-10-12</td>
<td style="text-align:right">167.3</td>
<td style="text-align:right">8</td>
<td style="text-align:right">1</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%v-stack-10-12</td>
<td style="text-align:right">185.0</td>
<td style="text-align:right">8</td>
<td style="text-align:right">1</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%+v-stack-10-12</td>
<td style="text-align:right">8680</td>
<td style="text-align:right">1401</td>
<td style="text-align:right">33</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%s-stack-30-12</td>
<td style="text-align:right">174.8</td>
<td style="text-align:right">8</td>
<td style="text-align:right">1</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%v-stack-30-12</td>
<td style="text-align:right">180.4</td>
<td style="text-align:right">8</td>
<td style="text-align:right">1</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%+v-stack-30-12</td>
<td style="text-align:right">8826</td>
<td style="text-align:right">1401</td>
<td style="text-align:right">33</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%s-stack-60-12</td>
<td style="text-align:right">170.0</td>
<td style="text-align:right">8</td>
<td style="text-align:right">1</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%v-stack-60-12</td>
<td style="text-align:right">160.5</td>
<td style="text-align:right">8</td>
<td style="text-align:right">1</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%+v-stack-60-12</td>
<td style="text-align:right">8636</td>
<td style="text-align:right">1401</td>
<td style="text-align:right">33</td>
</tr>
</tbody>
</table>
<p>うっ,アロケート回数が33回とか <code>orz</code></p>
<p>凹みつつも JSON データ生成部分でなるべく <a href="https://pkg.go.dev/fmt" title="fmt package - fmt - Go Packages"><code>fmt</code></a><code>.Sprintf</code> を使わないようにした v1.2.3 をリリースした。</p>
<ul>
<li><a href="https://github.com/goark/errs/releases/tag/v1.2.3">Release v1.2.3 · goark/errs · GitHub</a></li>
</ul>
<p>これを使って同じ条件でベンチマークをとってみたのだが</p>
<table>
<thead>
<tr>
<th>benchmark</th>
<th style="text-align:right">ns/op</th>
<th style="text-align:right">B/op</th>
<th style="text-align:right">allocs/op</th>
</tr>
</thead>
<tbody>
<tr>
<td>BenchmarkErrors/goark/errs-stack-10-12</td>
<td style="text-align:right">2850</td>
<td style="text-align:right">648</td>
<td style="text-align:right">7</td>
</tr>
<tr>
<td>BenchmarkErrors/goark/errs-stack-100-12</td>
<td style="text-align:right">3344</td>
<td style="text-align:right">648</td>
<td style="text-align:right">7</td>
</tr>
<tr>
<td>BenchmarkErrors/goark/errs-stack-1000-12</td>
<td style="text-align:right">6365</td>
<td style="text-align:right">648</td>
<td style="text-align:right">7</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%s-stack-10-12</td>
<td style="text-align:right">167.7</td>
<td style="text-align:right">8</td>
<td style="text-align:right">1</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%v-stack-10-12</td>
<td style="text-align:right">164.6</td>
<td style="text-align:right">8</td>
<td style="text-align:right">1</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%+v-stack-10-12</td>
<td style="text-align:right">7098</td>
<td style="text-align:right">1385</td>
<td style="text-align:right">31</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%s-stack-30-12</td>
<td style="text-align:right">171.8</td>
<td style="text-align:right">8</td>
<td style="text-align:right">1</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%v-stack-30-12</td>
<td style="text-align:right">171.5</td>
<td style="text-align:right">8</td>
<td style="text-align:right">1</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%+v-stack-30-12</td>
<td style="text-align:right">6974</td>
<td style="text-align:right">1385</td>
<td style="text-align:right">31</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%s-stack-60-12</td>
<td style="text-align:right">173.9</td>
<td style="text-align:right">8</td>
<td style="text-align:right">1</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%v-stack-60-12</td>
<td style="text-align:right">164.8</td>
<td style="text-align:right">8</td>
<td style="text-align:right">1</td>
</tr>
<tr>
<td>BenchmarkStackFormatting/goark/errs-%+v-stack-60-12</td>
<td style="text-align:right">7097</td>
<td style="text-align:right">1385</td>
<td style="text-align:right">31</td>
</tr>
</tbody>
</table>
<p>ちょっとしか変わらん <code>orz</code> やっぱ <a href="https://pkg.go.dev/encoding/json" title="json package - encoding/json - Go Packages"><code>json</code></a><code>.Marshal</code> を使ってるのがあかんのか? そもそも改善になってない?</p>
<p>…というわけで諦めました。
こんなのでよろしければ使ってやってください。</p>
<p>そうそう <a href="https://pkg.go.dev/errors" title="errors package - errors - Go Packages"><code>errors</code></a><code>.Join</code> 互換の関数ってあったほうがいいのかなぁ。
それをするにはマルチエラー用の型を作らないといけないのだが… これはちょっと考えてみてもいいかも。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://zenn.dev/spiegel/books/error-handling-in-golang">Go のエラーハンドリング</a></li>
<li><a href="https://text.baldanders.info/release/errs-package-for-golang/">Go 言語用エラーハンドリング・パッケージ</a></li>
<li><a href="https://text.baldanders.info/golang/zap-and-golog/">Zap と go-log を試す</a></li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4814400047?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41dClAl3WKL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4814400047?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">初めてのGo言語 ―他言語プログラマーのためのイディオマティックGo実践ガイド</a></dt>
<dd>Jon Bodner (著), 武舎 広幸 (翻訳)</dd>
<dd>オライリージャパン 2022-09-26</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4814400047 (ASIN), 9784814400041 (EAN), 4814400047 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="far fa-star"></i></abbr></dd>
</dl>
<p class="description">2021年に出た “<a href="https://www.oreilly.com/library/view/learning-go/9781492077206/">Learning Go</a>” の邦訳版。私は<a href="https://www.oreilly.co.jp/books/9784814400041/">版元</a>で PDF 版を購入。 Go 特有の語法(idiom)を切り口として Go の機能やパッケージを解説している。 Go 1.19 対応。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2022-10-11">2022-10-11</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 初めてのGo言語 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B09C2XBC2F?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/31PDIZXO9tL._SL160_.jpg" width="160" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B09C2XBC2F?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">デベロッパーゴースーパーゴラン Tシャツ</a></dt>
<dd>Geek Go Super Golang Tees</dd>
<dd>ウェア&シューズ</dd>
<dd>B09C2XBC2F (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="far fa-star"></i></abbr></dd>
</dl>
<p class="description">ついカッとなってポチった。反省はしない</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2022-04-10">2022-04-10</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- Golang Tシャツ -->
goark/errs パッケージ v1.2.1 をリリースした
tag:text.Baldanders.info,2023-02-08:/release/2023/02/errs-package-v1_2_1-is-released/
2023-02-08T03:45:17+00:00
2023-02-08T03:45:37+00:00
Go 1.20 でマルチエラーをサポートするようになったため,その対応
Spiegel
https://baldanders.info/profile/
<p>おそらく私しか使ってないであろう,エラーハンドリング用の <a href="https://github.com/goark/errs" title="goark/errs: Error handling for Golang"><code>/github.com/goark/errs</code></a> パッケージ v1.2.1 をリリースした。</p>
<ul>
<li><a href="https://github.com/goark/errs/releases/tag/v1.2.0">Release v1.2.0 · goark/errs · GitHub</a></li>
<li><a href="https://github.com/goark/errs/releases/tag/v1.2.1">Release v1.2.1 · goark/errs · GitHub</a></li>
</ul>
<p>実は v1.2.0 でチョンボして v1.2.1 として出し直している。
ごめんペコン。</p>
<p><a href="https://go.dev/">Go</a> 1.20 で <code>Unwrap() []error</code> メソッドを持つマルチエラーをサポートするようになったため,その対応。
たとえば,複数の原因エラーがある場合に,標準の <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a><code>.Join()</code> 関数などと組み合わせて</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s">"errors"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"fmt"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"io"</span>
</span></span><span class="line"><span class="cl"> <span class="s">"os"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="s">"github.com/goark/errs"</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">generateMultiError</span><span class="p">()</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">return</span> <span class="nx">errs</span><span class="p">.</span><span class="nf">New</span><span class="p">(</span><span class="s">"error with multiple causes"</span><span class="p">,</span> <span class="nx">errs</span><span class="p">.</span><span class="nf">WithCause</span><span class="p">(</span><span class="nx">errors</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">ErrInvalid</span><span class="p">,</span> <span class="nx">io</span><span class="p">.</span><span class="nx">EOF</span><span class="p">)))</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">generateMultiError</span><span class="p">()</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Println</span><span class="p">(</span><span class="nx">errors</span><span class="p">.</span><span class="nf">Is</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">io</span><span class="p">.</span><span class="nx">EOF</span><span class="p">))</span> <span class="c1">// true
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span>
</span></span></code></pre></div><p>てな感じに書くことができる。
ちなみに</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="o">:=</span> <span class="nf">generateMultiError</span><span class="p">()</span>
</span></span><span class="line hl"><span class="cl"> <span class="nx">fmt</span><span class="p">.</span><span class="nf">Printf</span><span class="p">(</span><span class="s">"%+v\n"</span><span class="p">,</span> <span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>と書き換えて実行すると</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ go run sample4.go | jq .
</span></span><span class="line"><span class="cl">{
</span></span><span class="line"><span class="cl"> "Type": "*errs.Error",
</span></span><span class="line"><span class="cl"> "Err": {
</span></span><span class="line"><span class="cl"> "Type": "*errors.errorString",
</span></span><span class="line"><span class="cl"> "Msg": "error with multiple causes"
</span></span><span class="line"><span class="cl"> },
</span></span><span class="line"><span class="cl"> "Context": {
</span></span><span class="line"><span class="cl"> "function": "main.generateMultiError"
</span></span><span class="line"><span class="cl"> },
</span></span><span class="line"><span class="cl"> "Cause": {
</span></span><span class="line"><span class="cl"> "Type": "*errors.joinError",
</span></span><span class="line"><span class="cl"> "Msg": "invalid argument\nEOF",
</span></span><span class="line"><span class="cl"> "Cause": [
</span></span><span class="line"><span class="cl"> {
</span></span><span class="line"><span class="cl"> "Type": "*errors.errorString",
</span></span><span class="line"><span class="cl"> "Msg": "invalid argument"
</span></span><span class="line"><span class="cl"> },
</span></span><span class="line"><span class="cl"> {
</span></span><span class="line"><span class="cl"> "Type": "*errors.errorString",
</span></span><span class="line"><span class="cl"> "Msg": "EOF"
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl"> ]
</span></span><span class="line"><span class="cl"> }
</span></span><span class="line"><span class="cl">}
</span></span></code></pre></div><p>マルチエラー部分もいい感じに JSON 出力できる。</p>
<p>以前の <a href="https://github.com/goark/errs" title="goark/errs: Error handling for Golang"><code>errs</code></a><code>.Cause()</code> 関数には <code>Deprecated</code> マークを付けた(マルチエラーに対応できないため)。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// Deprecated: should not be used
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">Cause</span><span class="p">(</span><span class="nx">err</span> <span class="kt">error</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">unwraped</span> <span class="o">:=</span> <span class="nx">errors</span><span class="p">.</span><span class="nf">Unwrap</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">unwraped</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="p">=</span> <span class="nx">unwraped</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p><code>Deprecated</code> マークを付けた型や関数を使用すると lint などで注意喚起してくれる。
便利。</p>
<p><a href="https://github.com/goark/errs" title="goark/errs: Error handling for Golang"><code>errs</code></a><code>.Cause()</code> 関数の代わりと言ってはナニだが <a href="https://github.com/goark/errs" title="goark/errs: Error handling for Golang"><code>errs</code></a><code>.Unwraps()</code> 関数を用意した。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">Unwraps</span><span class="p">(</span><span class="nx">err</span> <span class="kt">error</span><span class="p">)</span> <span class="p">[]</span><span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">es</span><span class="p">,</span> <span class="nx">ok</span> <span class="o">:=</span> <span class="nx">err</span><span class="p">.(</span><span class="kd">interface</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nf">Unwrap</span><span class="p">()</span> <span class="p">[]</span><span class="kt">error</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span> <span class="nx">ok</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">es</span><span class="p">.</span><span class="nf">Unwrap</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">e</span> <span class="o">:=</span> <span class="nx">errors</span><span class="p">.</span><span class="nf">Unwrap</span><span class="p">(</span><span class="nx">err</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">e</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">[]</span><span class="kt">error</span><span class="p">{</span><span class="nx">e</span><span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">nil</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>この関数を使えば原因エラーを <code>[]error</code> で返してくれる(原因エラーが単一の場合もスライスで返すので注意)。</p>
<p>マルチエラーを格納する独自の型を作ることも一瞬考えたが,標準の <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a><code>.Join()</code> 関数などで作れば必要十分だと思うし,足りなければ改めて考えるか。
ということで今回はここまで。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://text.baldanders.info/golang/wrapping-multiple-errors/">【Go 1.20 の予習】複数 error を返す Unwrap メソッドについて</a></li>
<li><a href="https://text.baldanders.info/release/errs-package-for-golang/">Go 言語用エラーハンドリング・パッケージ</a></li>
<li><a href="https://zenn.dev/spiegel/books/error-handling-in-golang">Go のエラーハンドリング</a> : Zenn 本書きました</li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4814400047?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41dClAl3WKL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4814400047?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">初めてのGo言語 ―他言語プログラマーのためのイディオマティックGo実践ガイド</a></dt>
<dd>Jon Bodner (著), 武舎 広幸 (翻訳)</dd>
<dd>オライリージャパン 2022-09-26</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4814400047 (ASIN), 9784814400041 (EAN), 4814400047 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="far fa-star"></i></abbr></dd>
</dl>
<p class="description">2021年に出た “<a href="https://www.oreilly.com/library/view/learning-go/9781492077206/">Learning Go</a>” の邦訳版。私は<a href="https://www.oreilly.co.jp/books/9784814400041/">版元</a>で PDF 版を購入。 Go 特有の語法(idiom)を切り口として Go の機能やパッケージを解説している。 Go 1.19 対応。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2022-10-11">2022-10-11</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 初めてのGo言語 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4873119693?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41cBKEBEYyL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4873119693?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">実用 Go言語 ―システム開発の現場で知っておきたいアドバイス</a></dt>
<dd>渋川 よしき (著), 辻 大志郎 (著), 真野 隼記 (著)</dd>
<dd>オライリージャパン 2022-04-22</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4873119693 (ASIN), 9784873119694 (EAN), 4873119693 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="far fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.oreilly.co.jp//books/9784873119694/">版元</a>のデジタル版を購入。 Go で躓きやすい点を解説していくのが<a href="https://forkwell.connpass.com/event/262394/">最初の動機</a>らしい。「◯◯するには」を調べる際にこの本を調べるといいかも。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2022-10-26">2022-10-26</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 実用 Go 言語 -->
【Go 1.20 の予習】複数 error を返す Unwrap メソッドについて
tag:text.Baldanders.info,2023-01-25:/golang/wrapping-multiple-errors/
2023-01-25T03:57:01+00:00
2023-02-08T03:45:37+00:00
Go 1.20 で errors パッケージの仕様が変わるみたいなので予習しておく。
Spiegel
https://baldanders.info/profile/
<p>おそらく 2022-02 にリリースされる <a href="https://go.dev/">Go</a> 1.20 で errors パッケージの仕様が変わるみたいなので予習しておく。</p>
<figure lang="en">
<blockquote><p><strong>Wrapping multiple errors</strong></p>
<p>Go 1.20 expands support for error wrapping to permit an error to wrap multiple other errors.</p>
<p>An error e can wrap more than one error by providing an <code>Unwrap</code> method that returns a <code>[]error</code>.</p>
<p>The <a href="https://tip.golang.org/pkg/errors/#Is"><code>errors.Is</code></a> and <a href="https://tip.golang.org/pkg/errors/#As"><code>errors.As</code></a> functions have been updated to inspect multiply wrapped errors.</p>
<p>The <a href="https://tip.golang.org/pkg/fmt/#Errorf"><code>fmt.Errorf</code></a> function now supports multiple occurrences of the <code>%w</code> format verb, which will cause it to return an error that wraps all of those error operands.</p>
<p>The new function <a href="https://tip.golang.org/pkg/errors/#Join"><code>errors.Join</code></a> returns an error wrapping a list of errors.</p>
</blockquote>
<figcaption><div>via <q><a href="https://tip.golang.org/doc/go1.20#errors">Go 1.20 Release Notes - The Go Programming Language</a></q></div></figcaption>
</figure>
<p>現行の <a href="https://pkg.go.dev/errors" title="errors package - errors - Go Packages"><code>errors</code></a><code>.Is()</code> および <a href="https://pkg.go.dev/errors" title="errors package - errors - Go Packages"><code>errors</code></a><code>.As()</code> 各関数では 対象となる error インスタンスについて型アサーションを行い <code>Unwrap() error</code> メソッドを含む型か否かで再帰的に処理を行っているが, <a href="https://go.dev/">Go</a> 1.20 からは,この評価に <code>Unwrap() []error</code> メソッドが加わる。</p>
<p>具体的にはこんな感じらしい。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="c1">// Is reports whether any error in err's tree matches target.
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// The tree consists of err itself, followed by the errors obtained by repeatedly
</span></span></span><span class="line"><span class="cl"><span class="c1">// calling Unwrap. When err wraps multiple errors, Is examines err followed by a
</span></span></span><span class="line"><span class="cl"><span class="c1">// depth-first traversal of its children.
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// An error is considered to match a target if it is equal to that target or if
</span></span></span><span class="line"><span class="cl"><span class="c1">// it implements a method Is(error) bool such that Is(target) returns true.
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// An error type might provide an Is method so it can be treated as equivalent
</span></span></span><span class="line"><span class="cl"><span class="c1">// to an existing error. For example, if MyError defines
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// func (m MyError) Is(target error) bool { return target == fs.ErrExist }
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// then Is(MyError{}, fs.ErrExist) returns true. See syscall.Errno.Is for
</span></span></span><span class="line"><span class="cl"><span class="c1">// an example in the standard library. An Is method should only shallowly
</span></span></span><span class="line"><span class="cl"><span class="c1">// compare err and the target and not call Unwrap on either.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">Is</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">target</span> <span class="kt">error</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">target</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">err</span> <span class="o">==</span> <span class="nx">target</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">isComparable</span> <span class="o">:=</span> <span class="nx">reflectlite</span><span class="p">.</span><span class="nf">TypeOf</span><span class="p">(</span><span class="nx">target</span><span class="p">).</span><span class="nf">Comparable</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">isComparable</span> <span class="o">&&</span> <span class="nx">err</span> <span class="o">==</span> <span class="nx">target</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">x</span><span class="p">,</span> <span class="nx">ok</span> <span class="o">:=</span> <span class="nx">err</span><span class="p">.(</span><span class="kd">interface</span><span class="p">{</span> <span class="nf">Is</span><span class="p">(</span><span class="kt">error</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">});</span> <span class="nx">ok</span> <span class="o">&&</span> <span class="nx">x</span><span class="p">.</span><span class="nf">Is</span><span class="p">(</span><span class="nx">target</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">switch</span> <span class="nx">x</span> <span class="o">:=</span> <span class="nx">err</span><span class="p">.(</span><span class="kd">type</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="kd">interface</span><span class="p">{</span> <span class="nf">Unwrap</span><span class="p">()</span> <span class="kt">error</span> <span class="p">}:</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="p">=</span> <span class="nx">x</span><span class="p">.</span><span class="nf">Unwrap</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">case</span> <span class="kd">interface</span><span class="p">{</span> <span class="nf">Unwrap</span><span class="p">()</span> <span class="p">[]</span><span class="kt">error</span> <span class="p">}:</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">for</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">x</span><span class="p">.</span><span class="nf">Unwrap</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">if</span> <span class="nf">Is</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">target</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">return</span> <span class="kc">true</span>
</span></span><span class="line hl"><span class="cl"> <span class="p">}</span>
</span></span><span class="line hl"><span class="cl"> <span class="p">}</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">return</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"> <span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// As finds the first error in err's tree that matches target, and if one is found, sets
</span></span></span><span class="line"><span class="cl"><span class="c1">// target to that error value and returns true. Otherwise, it returns false.
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// The tree consists of err itself, followed by the errors obtained by repeatedly
</span></span></span><span class="line"><span class="cl"><span class="c1">// calling Unwrap. When err wraps multiple errors, As examines err followed by a
</span></span></span><span class="line"><span class="cl"><span class="c1">// depth-first traversal of its children.
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// An error matches target if the error's concrete value is assignable to the value
</span></span></span><span class="line"><span class="cl"><span class="c1">// pointed to by target, or if the error has a method As(interface{}) bool such that
</span></span></span><span class="line"><span class="cl"><span class="c1">// As(target) returns true. In the latter case, the As method is responsible for
</span></span></span><span class="line"><span class="cl"><span class="c1">// setting target.
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// An error type might provide an As method so it can be treated as if it were a
</span></span></span><span class="line"><span class="cl"><span class="c1">// different error type.
</span></span></span><span class="line"><span class="cl"><span class="c1">//
</span></span></span><span class="line"><span class="cl"><span class="c1">// As panics if target is not a non-nil pointer to either a type that implements
</span></span></span><span class="line"><span class="cl"><span class="c1">// error, or to any interface type.
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="kd">func</span> <span class="nf">As</span><span class="p">(</span><span class="nx">err</span> <span class="kt">error</span><span class="p">,</span> <span class="nx">target</span> <span class="nx">any</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">target</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nb">panic</span><span class="p">(</span><span class="s">"errors: target cannot be nil"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">val</span> <span class="o">:=</span> <span class="nx">reflectlite</span><span class="p">.</span><span class="nf">ValueOf</span><span class="p">(</span><span class="nx">target</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="nx">typ</span> <span class="o">:=</span> <span class="nx">val</span><span class="p">.</span><span class="nf">Type</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">typ</span><span class="p">.</span><span class="nf">Kind</span><span class="p">()</span> <span class="o">!=</span> <span class="nx">reflectlite</span><span class="p">.</span><span class="nx">Ptr</span> <span class="o">||</span> <span class="nx">val</span><span class="p">.</span><span class="nf">IsNil</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nb">panic</span><span class="p">(</span><span class="s">"errors: target must be a non-nil pointer"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">targetType</span> <span class="o">:=</span> <span class="nx">typ</span><span class="p">.</span><span class="nf">Elem</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">targetType</span><span class="p">.</span><span class="nf">Kind</span><span class="p">()</span> <span class="o">!=</span> <span class="nx">reflectlite</span><span class="p">.</span><span class="nx">Interface</span> <span class="o">&&</span> <span class="p">!</span><span class="nx">targetType</span><span class="p">.</span><span class="nf">Implements</span><span class="p">(</span><span class="nx">errorType</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nb">panic</span><span class="p">(</span><span class="s">"errors: *target must be interface or implement error"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">reflectlite</span><span class="p">.</span><span class="nf">TypeOf</span><span class="p">(</span><span class="nx">err</span><span class="p">).</span><span class="nf">AssignableTo</span><span class="p">(</span><span class="nx">targetType</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">val</span><span class="p">.</span><span class="nf">Elem</span><span class="p">().</span><span class="nf">Set</span><span class="p">(</span><span class="nx">reflectlite</span><span class="p">.</span><span class="nf">ValueOf</span><span class="p">(</span><span class="nx">err</span><span class="p">))</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">x</span><span class="p">,</span> <span class="nx">ok</span> <span class="o">:=</span> <span class="nx">err</span><span class="p">.(</span><span class="kd">interface</span><span class="p">{</span> <span class="nf">As</span><span class="p">(</span><span class="nx">any</span><span class="p">)</span> <span class="kt">bool</span> <span class="p">});</span> <span class="nx">ok</span> <span class="o">&&</span> <span class="nx">x</span><span class="p">.</span><span class="nf">As</span><span class="p">(</span><span class="nx">target</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">true</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">switch</span> <span class="nx">x</span> <span class="o">:=</span> <span class="nx">err</span><span class="p">.(</span><span class="kd">type</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">case</span> <span class="kd">interface</span><span class="p">{</span> <span class="nf">Unwrap</span><span class="p">()</span> <span class="kt">error</span> <span class="p">}:</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="p">=</span> <span class="nx">x</span><span class="p">.</span><span class="nf">Unwrap</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">err</span> <span class="o">==</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">case</span> <span class="kd">interface</span><span class="p">{</span> <span class="nf">Unwrap</span><span class="p">()</span> <span class="p">[]</span><span class="kt">error</span> <span class="p">}:</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">for</span> <span class="nx">_</span><span class="p">,</span> <span class="nx">err</span> <span class="o">:=</span> <span class="k">range</span> <span class="nx">x</span><span class="p">.</span><span class="nf">Unwrap</span><span class="p">()</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">if</span> <span class="nf">As</span><span class="p">(</span><span class="nx">err</span><span class="p">,</span> <span class="nx">target</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">return</span> <span class="kc">true</span>
</span></span><span class="line hl"><span class="cl"> <span class="p">}</span>
</span></span><span class="line hl"><span class="cl"> <span class="p">}</span>
</span></span><span class="line hl"><span class="cl"> <span class="k">return</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"> <span class="k">default</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="kc">false</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>ちょっと長くて申し訳ないが,各関数の型 switch 文のなかで <code>Unwrap() []error</code> メソッドを含む型を評価しているのがおわかりだろうか。</p>
<p>標準パッケージでは新設の <a href="https://pkg.go.dev/errors" title="errors package - errors - Go Packages"><code>errors</code></a><code>.Join()</code> 関数や <a href="https://pkg.go.dev/fmt" title="fmt package - errors - Go Packages"><code>fmt</code></a><code>.Errorf()</code> 関数の拡張でマルチエラーに対応するようだが,自前で error 型を作る場合でも <code>Unwrap() []error</code> メソッドを追加することで <a href="https://pkg.go.dev/errors" title="errors package - errors - Go Packages"><code>errors</code></a><code>.Is()</code> 関数や <a href="https://pkg.go.dev/errors" title="errors package - errors - Go Packages"><code>errors</code></a><code>.As()</code> 関数による評価が可能になるわけだ。</p>
<h2>ブックマーク</h2>
<ul>
<li>
<p><a href="https://mattn.kaoriya.net/software/lang/go/20221001015441.htm">Big Sky :: errors.Join が入った。</a></p>
</li>
<li>
<p><a href="https://future-architect.github.io/articles/20230126a/">Go 1.20 Wrapping multiple errors | フューチャー技術ブログ</a></p>
</li>
<li>
<p><a href="https://zenn.dev/spiegel/books/error-handling-in-golang">Go のエラーハンドリング</a></p>
</li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4814400047?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41dClAl3WKL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4814400047?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">初めてのGo言語 ―他言語プログラマーのためのイディオマティックGo実践ガイド</a></dt>
<dd>Jon Bodner (著), 武舎 広幸 (翻訳)</dd>
<dd>オライリージャパン 2022-09-26</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4814400047 (ASIN), 9784814400041 (EAN), 4814400047 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="far fa-star"></i></abbr></dd>
</dl>
<p class="description">2021年に出た “<a href="https://www.oreilly.com/library/view/learning-go/9781492077206/">Learning Go</a>” の邦訳版。私は<a href="https://www.oreilly.co.jp/books/9784814400041/">版元</a>で PDF 版を購入。 Go 特有の語法(idiom)を切り口として Go の機能やパッケージを解説している。 Go 1.19 対応。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2022-10-11">2022-10-11</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 初めてのGo言語 -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4873119693?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/41cBKEBEYyL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4873119693?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">実用 Go言語 ―システム開発の現場で知っておきたいアドバイス</a></dt>
<dd>渋川 よしき (著), 辻 大志郎 (著), 真野 隼記 (著)</dd>
<dd>オライリージャパン 2022-04-22</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4873119693 (ASIN), 9784873119694 (EAN), 4873119693 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="far fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.oreilly.co.jp//books/9784873119694/">版元</a>のデジタル版を購入。 Go で躓きやすい点を解説していくのが<a href="https://forkwell.connpass.com/event/262394/">最初の動機</a>らしい。「◯◯するには」を調べる際にこの本を調べるといいかも。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2022-10-26">2022-10-26</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 実用 Go 言語 -->
spiegel-im-spiegel/errs パッケージ v1.0.4 をリリースした
tag:text.Baldanders.info,2021-07-15:/release/2021/07/errs-package-v1_0_4-is-released/
2021-07-15T11:42:27+00:00
2021-12-04T02:40:05+00:00
不具合修正。マジすんません 🙇
Spiegel
https://baldanders.info/profile/
<p>Zenn で <a href="https://github.com/pkg/errors" title="pkg/errors: Simple error handling primitives">pkg/errors</a> の不具合(?)について<a href="https://zenn.dev/nekoshita/articles/097e00c6d3d1c9#comment-1dd0f100389e4e" title="今goのエラーハンドリングを無難にしておく方法(2021.07現在)">教えてもらった</a>。</p>
<ul>
<li><a href="https://github.com/pkg/errors/issues/223">Unwrap doesn’t return the base error · Issue #223 · pkg/errors · GitHub</a></li>
</ul>
<p>これを見たときは完全に他人事だったのだが,よく考えたら拙作の <a href="https://github.com/spiegel-im-spiegel/errs" title="spiegel-im-spiegel/errs: Error handling for Golang">spiegel-im-spiegel/errs</a> では <a href="https://github.com/pkg/errors" title="pkg/errors: Simple error handling primitives">pkg/errors</a> の設計コンセプトを参考にしているのでもしかして… と思って調べたら別のところで不具合を見つけてしまった <code>orz</code></p>
<p>具体的には <a href="https://github.com/spiegel-im-spiegel/errs" title="spiegel-im-spiegel/errs: Error handling for Golang"><code>errs</code></a><code>.New()</code> 関数で生成したインスタンスに標準の <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a><code>.Unwrap()</code> をかけても 返り値が <code>nil</code> にならないというもの。
ちうわけで,修正版をリリースした。</p>
<ul>
<li><a href="https://github.com/spiegel-im-spiegel/errs/releases/tag/v1.0.4">Release v1.0.4 · spiegel-im-spiegel/errs · GitHub</a></li>
</ul>
<p>言い訳するなら,実際のエラーハンドリングで <a href="https://pkg.go.dev/errors" title="errors · pkg.go.dev"><code>errors</code></a><code>.Unwrap()</code> を使って手動でひとつずつ階層を遡るとかしないよね,普通。
いや,マジすんません <abbr class="emoji-chars" title="ペコン">🙇</abbr></p>
<p>エラーハンドリングについて,最近読んで面白いと思ったのが以下の記事。</p>
<ul>
<li><a href="https://zenn.dev/nobonobo/articles/0b722c9c2b18d5">Goエラーハンドリング戦略</a></li>
</ul>
<p>特にクラウド環境下でロギングと絡めたハンドリングは参考になるだろう。</p>
<p>この記事の中で「サードパーティのロガーやエラーハンドラは極力使わない」というのは半分くらいは同意。
でも,サードパーティの汎用パッケージじゃなくても,結局は対象となるツール・サービスの設計に合わせて「自分で作ったほうが早い」ってのはあるんだよなぁ。
だから私も自前で作ってるんだけど(笑)</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://text.baldanders.info/release/errs-package-for-golang/">Go 言語用エラーハンドリング・パッケージ</a></li>
<li><a href="https://zenn.dev/spiegel/books/error-handling-in-golang">Go のエラーハンドリング</a> : Zenn 本書きました</li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
Go 製のツールとパッケージをまとめてアップデートした
tag:text.Baldanders.info,2020-10-02:/release/2020/10/released-tools-and-packages-by-golang/
2020-10-02T07:40:54+00:00
2021-12-04T02:40:05+00:00
Update gpgpdump, books-data, gnkf, pa-api, aozora-api, openbd-api, gocli, and errs packages
Spiegel
https://baldanders.info/profile/
<p><a href="https://github.com/">GitHub</a> リポジトリにある <a href="https://go.dev/">Go 言語</a>製のツールやパッケージについて <a href="https://github.com/">GitHub</a> Actions で CI (Continuous Integration) を回す目処が立ったので,設定を変更しリリースし直すことにした。
今回リリースしたツール・パッケージのうち主なものは以下の通り。</p>
<ul>
<li><a href="https://github.com/spiegel-im-spiegel/gpgpdump/releases/tag/v0.9.1">Release v0.9.1 · spiegel-im-spiegel/gpgpdump · GitHub</a></li>
<li><a href="https://github.com/spiegel-im-spiegel/books-data/releases/tag/v0.5.8">Release v0.5.8 · spiegel-im-spiegel/books-data · GitHub</a></li>
<li><a href="https://github.com/spiegel-im-spiegel/gnkf/releases/tag/v0.1.3">Release v0.1.3 · spiegel-im-spiegel/gnkf · GitHub</a></li>
<li><a href="https://github.com/spiegel-im-spiegel/pa-api/releases/tag/v0.7.2">Release v0.7.2 · spiegel-im-spiegel/pa-api · GitHub</a></li>
<li><a href="https://github.com/spiegel-im-spiegel/aozora-api/releases/tag/v0.2.6">Release v0.2.6 · spiegel-im-spiegel/aozora-api · GitHub</a></li>
<li><a href="https://github.com/spiegel-im-spiegel/openbd-api/releases/tag/v0.2.6">Release v0.2.6 · spiegel-im-spiegel/openbd-api · GitHub</a></li>
<li><a href="https://github.com/spiegel-im-spiegel/gocli/releases/tag/v0.10.3">Release v0.10.3 · spiegel-im-spiegel/gocli · GitHub</a></li>
<li><a href="https://github.com/spiegel-im-spiegel/errs/releases/tag/v1.0.2">Release v1.0.2 · spiegel-im-spiegel/errs · GitHub</a></li>
</ul>
<p>若干 lint に叱られたり軽微なバグを指摘されたりしたものもあるが,機能上の追加・変更はない。</p>
<p>それじゃあ,次のステージに行きましょう♪</p>
<h2>ブックマーク</h2>
<ul>
<li>
<p><a href="https://text.baldanders.info/release/gpgpdump/">OpenPGP パケットを可視化する gpgpdump</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/release/books-data/">書籍データ取得ツール books-data</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/release/gnkf/">GNKF: Network Kanji Filter by Golang</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/release/pa-api-v5/">Go 言語用 PA-API v5 クライアント・パッケージ</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/release/aozora-api-package-for-golang/">Go 言語用青空文庫 API クライアント・パッケージ</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/release/openbd-api-package-for-golang/">Go 言語用 openBD クライアント・パッケージ</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/release/gocli-package-for-golang/">Go 言語用 CLI プログラミング支援パッケージ</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/release/errs-package-for-golang/">Go 言語用エラーハンドリング・パッケージ</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/golang/using-golangci-lint-action/">golangci-lint を GitHub Actions で使う</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/golang/check-for-vulns-in-golang-dependencies/">Go 依存パッケージの脆弱性検査</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/golang/cross-compiling-in-github-actions-with-goreleaser/">GitHub Actions でクロス・コンパイル(GoReleaser 編)</a></p>
</li>
<li>
<p><a href="https://text.baldanders.info/remark/2020/10/github-code-scanning-with-golang/">Go のコードでも GitHub Code Scanning が使えるらしい</a></p>
</li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B01MZ8UA8O?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/516hKjO3t-L._SL160_.jpg" width="160" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B01MZ8UA8O?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">射手座☆午後九時Don't be late</a></dt>
<dd>シェリル・ノーム starring May'n (メインアーティスト)</dd>
<dd>FlyingDog 2008-05-08 (Release 2017-01-16)</dd>
<dd>MP3 ダウンロード</dd>
<dd>B01MZ8UA8O (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="far fa-star"></i></abbr></dd>
</dl>
<p class="description">移動中に聴くとノリノリになれる(笑)</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2020-10-02">2020-10-02</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- 射手座☆午後九時 Don't be late -->
エラーハンドリング・パッケージ errs v1.0.0 他のリリース【Go 1.15 リリース記念】
tag:text.Baldanders.info,2020-08-13:/release/2020/08/errs-package-v1_0_0-is-released/
2020-08-13T00:48:44+00:00
2021-12-04T02:40:05+00:00
機能追加なし。不具合修正もなし。 go.mod と Travis CI 設定を変更しただけの簡単なお仕事デス。
Spiegel
https://baldanders.info/profile/
<p>この前 v0.7.0 を出したばかりだが,<a href="https://text.baldanders.info/release/2020/08/errs-package-v0_7_0-is-released/" title="Go 言語用エラーハンドリング・パッケージ errs v0.7.0 をリリースした">予告した</a>とおり, <a href="https://text.baldanders.info/release/2020/08/go-1_15-is-released/" title="">Go 1.15 リリース</a>を記念して <a href="https://github.com/spiegel-im-spiegel/errs" title="spiegel-im-spiegel/errs: Error handling for Golang">spiegel-im-spiegel/errs</a> パッケージのメジャー・バージョンを上げることにした。</p>
<ul>
<li><a href="https://github.com/spiegel-im-spiegel/errs/releases/tag/v1.0.0">Release v1.0.0 · spiegel-im-spiegel/errs · GitHub</a></li>
</ul>
<p>機能追加なし。
不具合修正もなし。
<code>go.mod</code> と <a href="https://travis-ci.org/" title="Travis CI - Test and Deploy Your Code with Confidence">Travis CI</a> の設定を変更して <a href="https://go.dev/">Go</a> 1.15 に対応させただけの簡単なお仕事デス。</p>
<p>今後は後方互換性をきちんと考えて改修していく予定です <code>m(_ _)m</code></p>
<p>ついでに <a href="https://github.com/spiegel-im-spiegel/errs" title="spiegel-im-spiegel/errs: Error handling for Golang">spiegel-im-spiegel/errs</a> パッケージを利用している主なパッケージやツールもバージョンを上げた。</p>
<ul>
<li><a href="https://github.com/spiegel-im-spiegel/pa-api/releases/tag/v0.7.1">Release v0.7.1 · spiegel-im-spiegel/pa-api · GitHub</a></li>
<li><a href="https://github.com/spiegel-im-spiegel/openbd-api/releases/tag/v0.2.5">Release v0.2.5 · spiegel-im-spiegel/openbd-api · GitHub</a></li>
<li><a href="https://github.com/spiegel-im-spiegel/aozora-api/releases/tag/v0.2.5">Release v0.2.5 · spiegel-im-spiegel/aozora-api · GitHub</a></li>
<li><a href="https://github.com/spiegel-im-spiegel/gpgpdump/releases/tag/v0.7.2">Release v0.7.2 · spiegel-im-spiegel/gpgpdump · GitHub</a></li>
<li><a href="https://github.com/spiegel-im-spiegel/books-data/releases/tag/v0.5.6">Release v0.5.6 · spiegel-im-spiegel/books-data · GitHub</a></li>
<li><a href="https://github.com/spiegel-im-spiegel/gnkf/releases/tag/v0.1.2">Release v0.1.2 · spiegel-im-spiegel/gnkf · GitHub</a></li>
<li><a href="https://github.com/spiegel-im-spiegel/mklink/releases/tag/v0.1.20">Release v0.1.20 · spiegel-im-spiegel/mklink · GitHub</a></li>
</ul>
<p>基本的には <a href="https://github.com/spiegel-im-spiegel/errs" title="spiegel-im-spiegel/errs: Error handling for Golang">spiegel-im-spiegel/errs</a> パッケージのバージョンを上げただけ。
まぁ <a href="https://text.baldanders.info/release/2020/08/errs-package-v0_7_0-is-released/" title="Go 言語用エラーハンドリング・パッケージ errs v0.7.0 をリリースした">v0.7.0 で後方互換性をぶっ壊している</a>ので,手直しが多かったけど(笑)</p>
<h2>32ビット・バイナリの提供を止めました</h2>
<p><a href="https://github.com/spiegel-im-spiegel/gpgpdump/" title="spiegel-im-spiegel/gpgpdump: OpenPGP packet visualizer">gpgpdump</a>, <a href="https://github.com/spiegel-im-spiegel/books-data/" title="spiegel-im-spiegel/books-data: Search for Books Data">books-data</a>, <a href="https://github.com/spiegel-im-spiegel/gnkf/" title="spiegel-im-spiegel/gnkf: Network Kanji Filter by Golang">gnkf</a>, <a href="https://github.com/spiegel-im-spiegel/mklink/" title="spiegel-im-spiegel/mklink: Make Link with Markdown Format">mklink</a> の各ツールはバイナリでの提供も行っているが,今回から32ビット・バイナリの提供を止めることにした(ARM アーキテクチャを除く)。</p>
<p>きっかけは <a href="https://go.dev/">Go</a> 1.15 で <code>darwin/386</code> のサポートが終了したこと。</p>
<figure lang="en">
<blockquote><q>As <a href="https://golang.org/doc/go1.14#darwin">announced</a> in the Go 1.14 release notes, Go 1.15 drops support for 32-bit binaries on macOS, iOS, iPadOS, watchOS, and tvOS (the <code>darwin/386</code> and <code>darwin/arm</code> ports). Go continues to support the 64-bit <code>darwin/amd64</code> and <code>darwin/arm64</code> ports</q>.</blockquote>
<figcaption><div>via <q><a href="https://golang.org/doc/go1.15">Go 1.15 Release Notes - The Go Programming Language</a></q></div></figcaption>
</figure>
<p>クロスコンパイルは <a href="https://goreleaser.com/">GoReleaser</a> を使ってるのでそんなに面倒ではないんだけど… もう32ビット流行らんべ。
Windows で古い32ビット機を(しかも拙作を)使ってる人は多分いないだろうし <a href="https://www.ubuntu.com/" title="The leading operating system for PCs, IoT devices, servers and the cloud | Ubuntu">Ubuntu</a> も最新 LTS では遂に32ビット・アーキテクチャのサポートを終了したしね。</p>
<p>まぁ Pure <a href="https://go.dev/">Go</a> で書いてるのでダウンロード&ビルドは難しくないし,たいした問題ではないだろう,うんうん。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://text.baldanders.info/release/gpgpdump/">OpenPGP パケットを可視化する gpgpdump</a></li>
<li><a href="https://text.baldanders.info/release/books-data/">書籍データ取得ツール books-data</a></li>
<li><a href="https://text.baldanders.info/release/gnkf/">GNKF: Network Kanji Filter by Golang</a></li>
<li><a href="https://text.baldanders.info/release/aozora-api-package-for-golang/">Go 言語用青空文庫 API クライアント・パッケージ</a></li>
<li><a href="https://text.baldanders.info/release/openbd-api-package-for-golang/">Go 言語用 openBD クライアント・パッケージ</a></li>
<li><a href="https://text.baldanders.info/release/pa-api-v5/">Go 言語用 PA-API v5 クライアント・パッケージ</a></li>
<li><a href="https://text.baldanders.info/release/errs-package-for-golang/">Go 言語用エラーハンドリング・パッケージ</a></li>
</ul>
<ul>
<li><a href="https://text.baldanders.info/golang/make-link-with-markdown-format/">Markdown 形式のリンクを生成するツールを作ってみた</a></li>
<li><a href="https://text.baldanders.info/golang/cross-compiling-in-travis-ci-with-goreleaser/">Travis CI でクロス・コンパイル(GoReleaser 編)</a></li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
Go 言語用エラーハンドリング・パッケージ errs v0.7.0 をリリースした
tag:text.Baldanders.info,2020-08-08:/release/2020/08/errs-package-v0_7_0-is-released/
2020-08-08T01:03:25+00:00
2021-12-04T02:40:05+00:00
Go 1.15 のリリースを待って,問題がなければこのまま v1.0 に格上げする予定である。
Spiegel
https://baldanders.info/profile/
<p>Go 言語用エラーハンドリング・パッケージ <a href="https://github.com/spiegel-im-spiegel/errs" title="spiegel-im-spiegel/errs: Error handling for Golang"><code>errs</code></a> の v0.7.0 をリリースした。</p>
<ul>
<li><a href="https://github.com/spiegel-im-spiegel/errs/releases/tag/v0.7.0">Release v0.7.0 · spiegel-im-spiegel/errs · GitHub</a></li>
</ul>
<p>「後方互換性? なにそれおいしいの?」って感じでド派手に書き換えている。
使い方は以下を参照のこと。</p>
<ul>
<li><a href="https://text.baldanders.info/release/errs-package-for-golang/">Go 言語用エラーハンドリング・パッケージ</a></li>
</ul>
<p>改めて紹介すると, <a href="https://github.com/spiegel-im-spiegel/errs" title="spiegel-im-spiegel/errs: Error handling for Golang">spiegel-im-spiegel/errs</a> は以下の設計コンセプトで作成・公開した <a href="https://go.dev/">Go 言語</a>用エラーハンドリング・パッケージである。</p>
<ul>
<li><a href="https://go.dev/">Go</a> 1.13 以降の標準パッケージ <code>errors</code> と置き換え可能</li>
<li>任意の <code>error</code> インスタンスをラッピング可能</li>
<li>任意の <code>error</code> インスタンスを原因エラーとして埋め込み可能</li>
<li>任意のコンテキスト情報を埋め込み可能
<ul>
<li>既定でエラーが発生した関数名をコンテキスト情報として保持する</li>
</ul>
</li>
<li>構造化されたエラー情報を JSON 形式で出力可能
<ul>
<li><code>MarshalJSON()</code> メソッド完備</li>
<li>書式 <code>%+v</code> を使って JSON 形式で出力</li>
<li>任意の <code>error</code> インスタンスで可能な限り構造を辿って出力</li>
</ul>
</li>
</ul>
<p>v0.7.0 で個人的に欲しい機能は全て搭載したので, <a href="https://go.dev/">Go</a> 1.15 の正式リリースを待って,問題がなければこのまま v1.0 に格上げする予定である。</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://text.baldanders.info/golang/error-handling-in-go-1_3/">Go 1.13 のエラー・ハンドリング</a></li>
<li><a href="https://text.baldanders.info/golang/formatting/">書式 %v のカスタマイズ</a></li>
<li><a href="https://text.baldanders.info/golang/logging-error/">構造化エラーをログ出力する</a></li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->
エラー・ハンドリングのキホン
tag:text.Baldanders.info,2020-04-06:/rust-lang/error-handling/
2020-04-06T12:11:43+00:00
2020-04-09T07:27:39+00:00
やっぱ例外処理は要らんよね(笑)
Spiegel
https://baldanders.info/profile/
<p>今日の起点となるコードはこれにしよう。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">parse_string</span><span class="p">(</span><span class="n">s</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">Result</span><span class="o"><</span><span class="kt">u32</span><span class="p">,</span><span class="w"> </span><span class="n">std</span>::<span class="n">num</span>::<span class="n">ParseIntError</span><span class="o">></span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">s</span><span class="p">.</span><span class="n">parse</span>::<span class="o"><</span><span class="kt">u32</span><span class="o">></span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{:?}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">parse_string</span><span class="p">(</span><span class="s">"-1"</span><span class="p">));</span><span class="w"> </span><span class="c1">//Output: Err(ParseIntError { kind: InvalidDigit })
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p><code>parse_string()</code> 関数の返り値の型 <code>Result</code> は列挙型 <code>enum</code> で<sup id="fnref:1"><a href="#fn:1" class="footnote-ref" role="doc-noteref">1</a></sup>,以下の2つの列挙子(variant)で構成されている。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">enum</span> <span class="nb">Result</span><span class="o"><</span><span class="n">T</span><span class="p">,</span><span class="w"> </span><span class="n">E</span><span class="o">></span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">T</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">E</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p><code>Result</code> など列挙型の評価には <code>match</code> 式を使う。
たとえば <code>parse()</code> に失敗した際に <code>0</code> をセットしたいなら</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">parse_string</span><span class="p">(</span><span class="s">"-1"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">_</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">);</span><span class="w"> </span><span class="c1">//Output: 0
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>などと書くことができる。</p>
<h2>Result 型を使ったエラー・ハンドリング</h2>
<p>このように <code>Result</code> 型を使うことで基本的なエラー・ハンドリングが可能になる。
いくつか例を挙げていこう。</p>
<h3>Panic を投げる</h3>
<p><code>parse_string()</code> 関数が <code>Err</code> を返した場合に強制終了したいのであれば</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">parse_string</span><span class="p">(</span><span class="s">"-1"</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="fm">panic!</span><span class="p">(</span><span class="n">e</span><span class="p">),</span><span class="w"> </span><span class="c1">//Output: thread 'main' panicked at 'Box<Any>', src/main.rs:8:19
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">);</span><span class="w"> </span><span class="c1">//do not reach
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>と <code>panic!</code> マクロで panic を投げればよい。
ちなみに,環境変数 <code>RUST_BACKTRACE</code> に <code>1</code> をセットすると panic 時にスタックトレース情報も吐く。</p>
<p>単に panic を投げればいいのであれば <code>Result::unwrap()</code> メソッドを使えば上述のコードとほぼ同じ結果が得られる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parse_string</span><span class="p">(</span><span class="s">"-1"</span><span class="p">).</span><span class="n">unwrap</span><span class="p">();</span><span class="w"> </span><span class="c1">//Output: thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }', src/main.rs:6:13
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">);</span><span class="w"> </span><span class="c1">//do not reach
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>Panic を投げる際のメッセージを指定するには <code>Result::expect()</code> メソッドを使う。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parse_string</span><span class="p">(</span><span class="s">"-1"</span><span class="p">).</span><span class="n">expect</span><span class="p">(</span><span class="s">"error in parse_string() function"</span><span class="p">);</span><span class="w"> </span><span class="c1">//Output: thread 'main' panicked at 'error in parse_string() function: ParseIntError { kind: InvalidDigit }', src/main.rs:6:13
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">);</span><span class="w"> </span><span class="c1">//do not reach
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><h3>Panic 以外のハンドリング</h3>
<p>エラー時に単に panic を投げるのではなく,何らかの処理を行って普通にプロセスを終了したいのであれば <code>Result::unwrap_or_else()</code> メソッドを使って</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parse_string</span><span class="p">(</span><span class="s">"-1"</span><span class="p">).</span><span class="n">unwrap_or_else</span><span class="p">(</span><span class="o">|</span><span class="n">e</span><span class="o">|</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"Error in parse_string() function: </span><span class="si">{:?}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">);</span><span class="w"> </span><span class="c1">//Output: Error in parse_string() function: ParseIntError { kind: InvalidDigit }
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="n">std</span>::<span class="n">process</span>::<span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">);</span><span class="w"> </span><span class="c1">//do not reach
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>などとすることもできる。
プロセスを終了するのではなく,最初の例のように解析失敗時に <code>0</code> をセットしたいなら</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parse_string</span><span class="p">(</span><span class="s">"-1"</span><span class="p">).</span><span class="n">unwrap_or_else</span><span class="p">(</span><span class="o">|</span><span class="n">_</span><span class="o">|</span><span class="w"> </span><span class="mi">0</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">);</span><span class="w"> </span><span class="c1">//Output: 0
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>てな感じにも書ける。
あるいはもっと簡単に <code>Result::unwrap_or()</code> メソッドを使って</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">parse_string</span><span class="p">(</span><span class="s">"-1"</span><span class="p">).</span><span class="n">unwrap_or</span><span class="p">(</span><span class="mi">0</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">);</span><span class="w"> </span><span class="c1">//Output: 0
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>とも書ける。</p>
<h3>エラーの委譲</h3>
<p>次に以下の関数を考える。
2つの数文字列を与えて組(tuple)にして返す。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">parse_pair_strings</span><span class="p">(</span><span class="n">s1</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">s2</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">Result</span><span class="o"><</span><span class="p">(</span><span class="kt">u32</span><span class="p">,</span><span class="w"> </span><span class="kt">u32</span><span class="p">),</span><span class="w"> </span><span class="n">std</span>::<span class="n">num</span>::<span class="n">ParseIntError</span><span class="o">></span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">s1</span><span class="p">.</span><span class="n">parse</span>::<span class="o"><</span><span class="kt">u32</span><span class="o">></span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">y</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">s2</span><span class="p">.</span><span class="n">parse</span>::<span class="o"><</span><span class="kt">u32</span><span class="o">></span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">n</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="n">n</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">e</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Ok</span><span class="p">((</span><span class="n">x</span><span class="p">,</span><span class="w"> </span><span class="n">y</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{:?}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">parse_pair_strings</span><span class="p">(</span><span class="s">"1"</span><span class="p">,</span><span class="w"> </span><span class="s">"-1"</span><span class="p">));</span><span class="w"> </span><span class="c1">//Output: Err(ParseIntError { kind: InvalidDigit })
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p><code>parse_pair_strings()</code> の仮引数 <code>s1</code> および <code>s2</code> に対してそれぞれ <code>parse()</code> を行うのだが,返り値が <code>Err</code> の際にはエラーをそのまま返して呼び出し元にハンドリングを委譲している。</p>
<p>返り値の型が同じ <code>Result</code> なら <code>?</code> 演算子を使ってエラーの委譲をもっと簡単に書くことができる。
こんな感じ。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">parse_pair_strings</span><span class="p">(</span><span class="n">s1</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">,</span><span class="w"> </span><span class="n">s2</span>: <span class="kp">&</span><span class="kt">str</span><span class="p">)</span><span class="w"> </span>-> <span class="nb">Result</span><span class="o"><</span><span class="p">(</span><span class="kt">u32</span><span class="p">,</span><span class="w"> </span><span class="kt">u32</span><span class="p">),</span><span class="w"> </span><span class="n">std</span>::<span class="n">num</span>::<span class="n">ParseIntError</span><span class="o">></span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line hl"><span class="cl"><span class="w"> </span><span class="nb">Ok</span><span class="p">((</span><span class="n">s1</span><span class="p">.</span><span class="n">parse</span>::<span class="o"><</span><span class="kt">u32</span><span class="o">></span><span class="p">()</span><span class="o">?</span><span class="p">,</span><span class="w"> </span><span class="n">s2</span><span class="p">.</span><span class="n">parse</span>::<span class="o"><</span><span class="kt">u32</span><span class="o">></span><span class="p">()</span><span class="o">?</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>すっきりー!</p>
<h3>エラーの汎化</h3>
<p>今度は,引数に文字列を渡すのではなく,標準入力から文字列を取得して <code>parse()</code> してみよう。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">parse_from_stdin</span><span class="p">()</span><span class="w"> </span>-> <span class="nb">Result</span><span class="o"><</span><span class="kt">u32</span><span class="p">,</span><span class="w"> </span><span class="n">std</span>::<span class="n">num</span>::<span class="n">ParseIntError</span><span class="o">></span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">buf</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line hl"><span class="cl"><span class="w"> </span><span class="n">std</span>::<span class="n">io</span>::<span class="n">stdin</span><span class="p">().</span><span class="n">read_line</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="n">buf</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w"> </span><span class="c1">//Compile error: `?` couldn't convert the error to `std::num::ParseIntError`
</span></span></span><span class="line"><span class="cl"><span class="c1"></span><span class="w"> </span><span class="n">buf</span><span class="p">.</span><span class="n">trim</span><span class="p">().</span><span class="n">parse</span>::<span class="o"><</span><span class="kt">u32</span><span class="o">></span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>当然ながらこれはコンパイルエラーになる。
何故なら <code>read_line()</code> 関数では <code>Err</code> の値が <code>std::io::Error</code> 型になるので <code>std::num::ParseIntError</code> 型とはマッチしないためだ。</p>
<p>これを解決するには <code>std::error::Error</code> 型を汎化型として使えばよい。</p>
<figure style='margin:0 auto;text-align:center;'><a href="./error-trait.puml"><img src="./error-trait.png" srcset="./error-trait.png 1059w" sizes="(min-width:600px) 500px, 80vw" alt="" loading="lazy"></a></figure>
<p><code>std::error::Error</code> 型を使う際は <code>Box<dyn Trait></code> にするようだ。
こんな感じ。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line hl"><span class="cl"><span class="k">fn</span> <span class="nf">parse_from_stdin</span><span class="p">()</span><span class="w"> </span>-> <span class="nb">Result</span><span class="o"><</span><span class="kt">u32</span><span class="p">,</span><span class="w"> </span><span class="nb">Box</span><span class="o"><</span><span class="k">dyn</span><span class="w"> </span><span class="n">std</span>::<span class="n">error</span>::<span class="n">Error</span><span class="o">>></span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="k">mut</span><span class="w"> </span><span class="n">buf</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="nb">String</span>::<span class="n">new</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">std</span>::<span class="n">io</span>::<span class="n">stdin</span><span class="p">().</span><span class="n">read_line</span><span class="p">(</span><span class="o">&</span><span class="k">mut</span><span class="w"> </span><span class="n">buf</span><span class="p">)</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">buf</span><span class="p">.</span><span class="n">trim</span><span class="p">().</span><span class="n">parse</span>::<span class="o"><</span><span class="kt">u32</span><span class="o">></span><span class="p">()</span><span class="o">?</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">n</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{:?}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">parse_from_stdin</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>実行するとこんな感じになる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ echo -1 | cargo run
</span></span><span class="line"><span class="cl">Err(ParseIntError { kind: InvalidDigit })
</span></span></code></pre></div><p><code>main()</code> 関数側でもう少し細かくエラーを見てみよう。
こんな感じかなぁ。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">n</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">parse_from_stdin</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Ok</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="n">x</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Err</span><span class="p">(</span><span class="n">err</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">err</span><span class="p">.</span><span class="n">downcast_ref</span>::<span class="o"><</span><span class="n">std</span>::<span class="n">io</span>::<span class="n">Error</span><span class="o">></span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"io::Error in parse_from_stdin(): </span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">std</span>::<span class="n">process</span>::<span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">err</span><span class="p">.</span><span class="n">downcast_ref</span>::<span class="o"><</span><span class="n">std</span>::<span class="n">num</span>::<span class="n">ParseIntError</span><span class="o">></span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"ParseIntError in parse_from_stdin(): </span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">e</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">std</span>::<span class="n">process</span>::<span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">_</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="p">(),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"Other error in parse_from_stdin(): </span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">err</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">std</span>::<span class="n">process</span>::<span class="n">exit</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">n</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>こうすれば <code>Box<dyn std::error::Error></code> 型からもとのエラー型を抽出して個別に処理できそう。
これを実行するとこんな感じ。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ echo -1 | cargo run
</span></span><span class="line"><span class="cl">ParseIntError in parse_from_stdin(): invalid digit found in string
</span></span></code></pre></div><p>んー。
かなり面倒くさいな。
もう少しマシな戦略を探すべきか。</p>
<h2>Option 型を使ったエラー・ハンドリング</h2>
<p>上述のコードにある <code>downcast_ref()</code> メソッドは <code>Option</code> 型の値を返す。
<code>Option</code> 型も列挙型で,以下の2つの列挙子で構成されている。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">enum</span> <span class="nb">Option</span><span class="o"><</span><span class="n">T</span><span class="o">></span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">T</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">None</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p><code>None</code> はいわゆる Null 値,つまり値がないことを示す。
関数の実行結果が Null 値を取り得る場合に <code>Option</code> 型を返すことで,呼び出し元に Null 値のハンドリングを促すことができる。</p>
<p>起点のコードはこんな感じでどうだろうか。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">nihongo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"日本語"</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="o">..</span><span class="mi">4</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{}</span><span class="s">: </span><span class="si">{:?}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">nihongo</span><span class="p">.</span><span class="n">chars</span><span class="p">().</span><span class="n">nth</span><span class="p">(</span><span class="n">i</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>実行するとこんな感じになる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ cargo run
</span></span><span class="line"><span class="cl">0: Some('日')
</span></span><span class="line"><span class="cl">1: Some('本')
</span></span><span class="line"><span class="cl">2: Some('語')
</span></span><span class="line"><span class="cl">3: None
</span></span></code></pre></div><h3>Panic を投げる</h3>
<p>結果が <code>None</code> なら panic を投げるようにしてみる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">nihongo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"日本語"</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="o">..</span><span class="mi">4</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">nihongo</span><span class="p">.</span><span class="n">chars</span><span class="p">().</span><span class="n">nth</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">c</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="n">c</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">None</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="fm">panic!</span><span class="p">(</span><span class="s">"Out of bounds"</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{}</span><span class="s">: </span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">ch</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><p>実行するとこんな感じ。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ cargo run
</span></span><span class="line"><span class="cl">0: 日
</span></span><span class="line"><span class="cl">1: 本
</span></span><span class="line"><span class="cl">2: 語
</span></span><span class="line"><span class="cl">thread 'main' panicked at 'Out of bounds', src/main.rs:6:21
</span></span></code></pre></div><p>また <code>Option</code> 型にも <code>unwrap()</code> や <code>expect()</code> といったメソッドがあり, <code>None</code> が返ったら panic を投げる。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">nihongo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"日本語"</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="o">..</span><span class="mi">4</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{}</span><span class="s">: </span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">nihongo</span><span class="p">.</span><span class="n">chars</span><span class="p">().</span><span class="n">nth</span><span class="p">(</span><span class="n">i</span><span class="p">).</span><span class="n">expect</span><span class="p">(</span><span class="s">"Out of bounds"</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ cargo run
</span></span><span class="line"><span class="cl">0: 日
</span></span><span class="line"><span class="cl">1: 本
</span></span><span class="line"><span class="cl">2: 語
</span></span><span class="line"><span class="cl">thread 'main' panicked at 'Out of bounds', src/main.rs:4:31
</span></span></code></pre></div><h3>Panic 以外のハンドリング</h3>
<p>たとえば,こんな感じかな。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-rust" data-lang="rust"><span class="line"><span class="cl"><span class="k">fn</span> <span class="nf">main</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">nihongo</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"日本語"</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">i</span><span class="w"> </span><span class="k">in</span><span class="w"> </span><span class="mi">0</span><span class="o">..</span><span class="mi">4</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">let</span><span class="w"> </span><span class="n">ch</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">match</span><span class="w"> </span><span class="n">nihongo</span><span class="p">.</span><span class="n">chars</span><span class="p">().</span><span class="n">nth</span><span class="p">(</span><span class="n">i</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nb">Some</span><span class="p">(</span><span class="n">c</span><span class="p">)</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="n">c</span><span class="p">,</span><span class="w">
</span></span></span><span class="line hl"><span class="cl"><span class="w"> </span><span class="nb">None</span><span class="w"> </span><span class="o">=></span><span class="w"> </span><span class="k">break</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">};</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="fm">println!</span><span class="p">(</span><span class="s">"</span><span class="si">{}</span><span class="s">: </span><span class="si">{}</span><span class="s">"</span><span class="p">,</span><span class="w"> </span><span class="n">i</span><span class="p">,</span><span class="w"> </span><span class="n">ch</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"></span><span class="p">}</span><span class="w">
</span></span></span></code></pre></div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ cargo run
</span></span><span class="line"><span class="cl">0: 日
</span></span><span class="line"><span class="cl">1: 本
</span></span><span class="line"><span class="cl">2: 語
</span></span></code></pre></div><p>まぁイテレータやコレクションでこんな書き方する人はおらんじゃろうけど。
あンまりいい例示じゃなくてすまん。</p>
<h2>やっぱ例外処理は要らんよね</h2>
<p><a href="https://www.rust-lang.org/" title="Rust Programming Language">Rust</a> の列挙型は(C/C++ や Java などと異なり)型の列挙を行い,パターン・マッチングによって処理を振り分ける。
この仕組みを上手く使ってエラー・ハンドリングを行っているわけだ。</p>
<p>こうやってみると,やっぱ例外処理は要らんよね(笑)</p>
<h2>ブックマーク</h2>
<ul>
<li><a href="https://hideoka.hateblo.jp/entry/2019/11/17/224953">Rustのエラーハンドリングの基本 - hideoka’s blog</a></li>
<li><a href="https://qiita.com/legokichi/items/d4819f7d464c0d2ce2b8">Rust のエラーまわりの変遷 - Qiita</a></li>
<li><a href="https://qiita.com/taiki-e/items/39688f6c86b919988222">Rustで複数のimpl Traitを返す - Qiita</a></li>
</ul>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4048930702?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51YLqKD4N5L._SL160_.jpg" width="124" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4048930702?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Rust 公式ガイド</a></dt>
<dd>Steve Klabnik (著), Carol Nichols (著), 尾崎 亮太 (翻訳)</dd>
<dd>KADOKAWA 2019-06-28 (Release 2019-06-28)</dd>
<dd>単行本</dd>
<dd>4048930702 (ASIN), 9784048930703 (EAN), 4048930702 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="far fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://doc.rust-lang.org/book/">公式ドキュメント</a>の日本語版。索引がちゃんとしているので,紙の本を買っておいて手元に置いておくのが吉。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2020-02-24">2020-02-24</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Rust 公式ガイド -->
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/4873118557?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/51vpZLDJAAL._SL160_.jpg" width="125" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/4873118557?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミングRust</a></dt>
<dd>Jim Blandy (著), Jason Orendorff (著), 中田 秀基 (翻訳)</dd>
<dd>オライリージャパン 2018-08-10</dd>
<dd>単行本(ソフトカバー)</dd>
<dd>4873118557 (ASIN), 9784873118550 (EAN), 4873118557 (ISBN)</dd>
<dd>評価<abbr class="rating fa-sm" title="4"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="far fa-star"></i></abbr></dd>
</dl>
<p class="description"><a href="https://www.oreilly.co.jp/books/9784873118550/">Eブック版</a>あり。<a href="https://doc.rust-lang.org/book/">公式ドキュメント</a>よりも系統的に書かれているので痒いところに手が届く感じ。ただし量が多いので,一度斜め読みしたらあとは傍らに置いて必要に応じてつまみ食いしていくのがいいだろう。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2020-03-08">2020-03-08</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミングRust -->
<div class="footnotes" role="doc-endnotes">
<hr>
<ol>
<li id="fn:1">
<p>列挙型については「<a href="https://text.baldanders.info/rust-lang/types/">Rust の型に関する覚え書き</a>」を参照のこと。 <a href="#fnref:1" class="footnote-backref" role="doc-backlink">↩︎</a></p>
</li>
</ol>
</div>
Go 1.13.6 がリリースされた,他
tag:text.Baldanders.info,2020-01-13:/release/2020/01/go-1_13_6-is-released/
2020-01-13T04:14:28+00:00
2021-12-04T02:40:05+00:00
他にも pkg/errors v0.9.0 がリリースされたようだ。
Spiegel
https://baldanders.info/profile/
<p>遅まきながら(笑)</p>
<p><a href="https://go.dev/">Go</a> 1.13.6 がリリースされた。</p>
<ul>
<li><a href="https://groups.google.com/forum/#!topic/golang-announce/RLFrcJ_FZZs">Go 1.13.6 and Go 1.12.15 are released - Google Group</a></li>
</ul>
<p>今回もセキュリティ・アップデートはなし。</p>
<figure lang="en">
<blockquote><q>go1.13.6 (released 2020/01/09) includes fixes to the runtime and the <code>net/http</code> package. See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.13.6+label%3ACherryPickApproved">Go 1.13.6 milestone</a> on our issue tracker for details</q>.</blockquote>
<figcaption><div>via <q><a href="https://golang.org/doc/devel/release.html#go1.13.minor">Release History - The Go Programming Language</a></q></div></figcaption>
</figure>
<p>例によって <a href="https://www.ubuntu.com/" title="The leading operating system for PCs, IoT devices, servers and the cloud | Ubuntu">Ubuntu</a> の APT で管理している <a href="https://go.dev/">Go</a> コンパイラは古いので,<a href="https://golang.org/dl/" title="Downloads - The Go Programming Language">ダウンロードページ</a>からバイナリ(<a href="https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz"><code>go1.13.6.linux-amd64.tar.gz</code></a>)を取ってきて手動でインストールすることを強く推奨する。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">$ cd /usr/local/src
</span></span><span class="line"><span class="cl">$ sudo curl "https://dl.google.com/go/go1.13.6.linux-amd64.tar.gz" -O
</span></span><span class="line"><span class="cl">$ cd ..
</span></span><span class="line"><span class="cl">$ sudo unlink go # 以前の Go が入っている場合
</span></span><span class="line"><span class="cl">$ sudo tar xvf src/go1.13.6.linux-amd64.tar.gz
</span></span><span class="line"><span class="cl">$ sudo mv go go1.13.6
</span></span><span class="line"><span class="cl">$ sudo ln -s go1.13.6 go
</span></span><span class="line"><span class="cl">$ go version # /usr/local/go/bin にパスが通っている場合
</span></span><span class="line"><span class="cl">go version go1.13.6 linux/amd64
</span></span></code></pre></div><p>アップデートは計画的に。</p>
<h2>pkg/errors v0.9.0 がリリースされた</h2>
<p><a href="https://github.com/pkg/errors" title="pkg/errors: Simple error handling primitives">pkg/errors</a> の v0.9.0 がリリースされたようだ。</p>
<figure lang="en">
<blockquote><q>errors 0.9.0 is a preparation release for a 1.0 final release. Also we were working on removing support for Go 1.8, 1.9 and 1.10 and earlier, and become compatible this package with new way of errors on Go 1.13</q>.</blockquote>
<figcaption><div>via <q><a href="https://github.com/pkg/errors/releases/tag/v0.9.0">Release errors 0.9.0 · pkg/errors</a></q></div></figcaption>
</figure>
<p>おおっ!</p>
<p>中身を見ると,標準の <a href="https://golang.org/pkg/errors/" title="errors - The Go Programming Language"><code>errors</code></a><code>.Is()</code>, <a href="https://golang.org/pkg/errors/" title="errors - The Go Programming Language"><code>errors</code></a><code>.As()</code>, および <a href="https://golang.org/pkg/errors/" title="errors - The Go Programming Language"><code>errors</code></a><code>.Unwrap()</code> 各関数を置き換え可能になっていて,さらに <a href="https://github.com/pkg/errors" title="pkg/errors: Simple error handling primitives">pkg/errors</a> の特徴である <code>Cause()</code> 関数も使えるようになっている。</p>
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="cl"><span class="kd">func</span> <span class="nf">Cause</span><span class="p">(</span><span class="nx">err</span> <span class="kt">error</span><span class="p">)</span> <span class="kt">error</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kd">type</span> <span class="nx">causer</span> <span class="kd">interface</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nf">Cause</span><span class="p">()</span> <span class="kt">error</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="nx">err</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="nx">cause</span><span class="p">,</span> <span class="nx">ok</span> <span class="o">:=</span> <span class="nx">err</span><span class="p">.(</span><span class="nx">causer</span><span class="p">);</span> <span class="nx">ok</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="p">=</span> <span class="nx">cause</span><span class="p">.</span><span class="nf">Cause</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="nx">unwrapped</span> <span class="o">:=</span> <span class="nf">Unwrap</span><span class="p">(</span><span class="nx">err</span><span class="p">);</span> <span class="nx">unwrapped</span> <span class="o">!=</span> <span class="kc">nil</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">err</span> <span class="p">=</span> <span class="nx">unwrapped</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">break</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="nx">err</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span></code></pre></div><p>ふむむー。
拙作の <a href="https://github.com/spiegel-im-spiegel/errs" title="spiegel-im-spiegel/errs: Error handling for Golang">spiegel-im-spiegel/errs</a> の <code>Cause()</code> 関数もこれに追従しておこうかな。
いや <a href="https://github.com/pkg/errors" title="pkg/errors: Simple error handling primitives">pkg/errors</a> の <code>*.Cause()</code> メソッドって <code>*.Unwrap()</code> メソッドと等価みたいだし,無理に合わせないほうがいいか。</p>
<h2>参考図書</h2>
<div class="hreview">
<div class="photo"><a href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1"><img src="https://m.media-amazon.com/images/I/416Stewy0NS._SL160_.jpg" width="123" alt="photo"></a></div>
<dl>
<dt class="item"><a class="fn url" href="https://www.amazon.co.jp/dp/B099928SJD?tag=baldandersinf-22&linkCode=ogi&th=1&psc=1">プログラミング言語Go</a></dt>
<dd>アラン・ドノバン (著), ブライアン・カーニハン (著), 柴田芳樹 (著)</dd>
<dd>丸善出版 2016-06-20 (Release 2021-07-13)</dd>
<dd>Kindle版</dd>
<dd>B099928SJD (ASIN)</dd>
<dd>評価<abbr class="rating fa-sm" title="5"> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i> <i class="fas fa-star"></i></abbr></dd>
</dl>
<p class="description">Kindle 版出た! 一部内容が古びてしまったが,この本は Go 言語の教科書と言ってもいいだろう。感想は<a href="https://text.baldanders.info/remark/2016/07/go-programming-language/" >こちら</a>。</p>
<p class="powered-by">reviewed by <a href='#maker' class='reviewer'>Spiegel</a> on <abbr class="dtreviewed" title="2021-05-22">2021-05-22</abbr> (powered by <a href="https://affiliate.amazon.co.jp/assoc_credentials/home">PA-APIv5</a>)</p>
</div> <!-- プログラミング言語Go -->