Programmingバックエンド開発者

panic/recoverとGoの標準的なエラーハンドリングの詳しい比較を示してください:違い、ベストプラクティス、落とし穴。panicを使用することが正当化されるのはどのような場合ですか?

Hintsage AIアシスタントで面接を突破

回答。

Goの標準的なアプローチは、返される値errorを介してエラーを処理することです。これにより、エラーが発生したときに各ポイントで何をすべきかを明示的に制御できます。panicは、予期しない壊滅的な状況を処理するためのメカニズムです:これは、最近のdeferまでの実行を中断し、recoverを使用して「救出」できます。しかし、recoverはdefer内でのみ機能します。

ベストプラクティス:

  • 通常の状況や予期されるエラー(ファイルが見つからない、リクエストが無効)にはerrorを使用すること。
  • panicは、作業を続けられない致命的な障害がある場合のみ使用すること(例えば、不変条件の違反、初期化のエラーなど)。
  • 通常のフロー(例えば、データの検証)にはpanicを使用しないこと。
func safeDivide(a, b int) (int, error) { if b == 0 { return 0, errors.New("ゼロで割ることはできません") } return a/b, nil } func mustDivide(a, b int) int { if b == 0 { panic("ゼロで割ることはできません!") } return a/b }

隠れた質問。

プログラムの任意の場所でrecoverを使ってどんなpanicエラーも「捕まえる」ことができますか?

回答: いいえ、recoverはdefer内でのみ機能し、panicが発生した同じゴルーチン内でのみ機能します。他の場合では、panicはその(またはすべての)ゴルーチンの実行を終了します — これはしばしば予期しないことになります。

このテーマの詳細を知らないために発生した実際のエラーの例。


物語

REST APIでは、ビジネスロジックの通常のエラー処理にpanicを使用しました。これにより、アプリケーションが不明瞭にクラッシュし、recoverが常に正しく機能しなかったため、不正確なログが生成されました。


物語

決済処理サービスでは、すべてのpanicを「捕まえる」ためにmain関数でdefer + recoverを実装しましたが、ゴルーチンを忘れました — 子ゴルーチン内でdefer/recoverなしにアプリケーションが「恐ろしい」エラーでクラッシュし、一部のトランザクションが不整合な状態に残されました。


物語

複雑な構造体のパーサーでエラーを返すのを忘れ、panicに置き換えました — これにより保守とテストが難しくなり、詳細なログと適切なUXを確保するためにエラー処理を完全に書き直さざるを得ませんでした。