技術メモ

技術メモ

ラフなメモ

Goのエラーの生成方法

Go でエラーを生成するときにどのように生成するのがいいのか、少し考えました。

私はエラーを扱うときはたいてい pkg/errors を使うようにしています。エラーをスタックできるのが便利ですよね。 エラーの起点になるときには fmt.Errorf()errors.New() でエラーを生成すると思いますが、どちらがよいのでしょうか?

個人的な考え

サンプル実装で考えてみます。どちらも error インターフェースの Error() string を実装しているので機能としては同等と言えるでしょう。現時点での結論は、errors.New を使えばいいのでは?と思っています。

package main

import (
    "fmt"

    "github.com/pkg/errors"
)

func errorByFmtErrorF() error {
    return fmt.Errorf("Error: %s", "fmt.Errorf")
}

func errorByErrorsNew() error {
    return errors.New(fmt.Sprintf("Error: %s", "errors.New"))
}

func main() {
    // どちらも error インターフェースを満たしていて、機能としては同等
    fmt.Printf("fmt.Errorf: %v\n", errorByFmtErrorF())
    fmt.Printf("errors.New: %v\n", errorByErrorsNew())
}
  • 出力結果
fmt.Errorf: Error: fmt.Errorf
errors.New: Error: errors.New

まぁこのあたりはコードスタイルな気もします。

uber-go の guide にもエラーの扱いが書いてあるので、参考になりそうです。(翻訳版から引用しておきます

uber-style-guide-ja/guide.md at master · knsh14/uber-style-guide-ja · GitHub

  • このエラーは追加情報が必要ないか?もし無いなら、errors.New で十分です。
  • 利用する側がエラーを検知してハンドリングする必要がありますか?その場合自前で Error() メソッドを実装した型を作る必要があります。
  • 下流のエラーを更に上流に返していますか?もしそうなら、section on error wrapping. の章を参考にしてください。
  • これらに当てはまらないなら、fmt.Errorf で問題ないでしょう。

その他参考