Goの標準的なアプローチは、返される値errorを介してエラーを処理することです。これにより、エラーが発生したときに各ポイントで何をすべきかを明示的に制御できます。panicは、予期しない壊滅的な状況を処理するためのメカニズムです:これは、最近のdeferまでの実行を中断し、recoverを使用して「救出」できます。しかし、recoverはdefer内でのみ機能します。
ベストプラクティス:
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を確保するためにエラー処理を完全に書き直さざるを得ませんでした。