Goでは、関数から型errorの値を返す標準的なエラー処理のアプローチがあります。例外のある言語とは異なり、Goでは例外(panic, recover)は真に例外的な状況にのみ使用されます。ビジネスロジックには通常のエラーを使用する必要があります。
古典的な方法:
func doSomething() error { // ... return nil // または errors.New("some error") } err := doSomething() if err != nil { // エラー処理 }
より詳細な分析のために、カスタムエラータイプを作成することができます:
type MyError struct { Code int Message string } func (e *MyError) Error() string { return fmt.Sprintf("(%d) %s", e.Code, e.Message) } err := &MyError{404, "not found"}
特定のエラーを確認する一般的な方法:
if myErr, ok := err.(*MyError); ok && myErr.Code == 404 { // 404エラー処理 }
Goでエラーをnilと比較することはできますか?
回答: はい、エラーがないかを確認するために可能で必要です。しかし、注意が必要です:エラーがラップされたり、構造体内部にnilを含むエラーが作成されている場合、比較が誤っている可能性があります。例えば:
var err error = (*MyError)(nil) fmt.Println(err == nil) // false!
インターフェイスはその型がnilでない限りnilと等しくないため、内部がnilでも同様です。
逸話
マイクロサービスはnilとの比較を通じてエラーをログしていました。開発者の一人が、(*MyError)(nil)のような型付きエラーを返したところ、これがnilに等しくないことに気付かず、エラー処理が機能しなくなり、多くの誤報告がメトリクスに影響を及ぼしました。
逸話
プロジェクトではエラーをチェーンで渡す代わりに、すべてのエラーについてpanicを使用し、これが「クリーンな」方法だと考えていました。これにより、ユーザーの不正な入力ごとにアプリケーションがクラッシュすることになりました。というのも、panic/recoverはストリームビジネスロジックに適していないからです。
逸話
エラーがfmt.Errorf("some: %w", err)を使用して数回ラップされ、特定のエラータイプを確認するときに通常の比較を行い、errors.Isやerrors.Asを使用せずに行われました。これにより、ビジネスロジックはカスタムエラータイプに反応しなくなり、ラップされたエラーの内部にそれらが実際に存在しているにもかかわらずです。