Goは、例外の代わりに明示的なエラーの返却を中心に設計されてきました。これにより、予測可能なコードが作成され、他の言語のtry/catch構文に見られる隠れた罠を避けることができます(例えば、JavaやC++など)。Goにおけるエラーは、Error()メソッドを実装するインターフェースであり、簡単なエラーや文脈を持つ複合エラー/ラップエラーを作成することができます。
問題は、エラーを適切に処理しない(例えば、_で無視する、デバッグ情報を付加せずにラップしない)場合や、エラーインターフェースに準拠しない「魔法の」エラーを生成する場合に発生します。また、パブリック関数からエラーを返し、各呼び出し時にエラーを確認することが重要です。
解決策は、標準的なアプローチを使用することです:
コード例:
import ( "errors" "fmt" ) type NotFoundError struct { Resource string } func (e *NotFoundError) Error() string { return fmt.Sprintf("%sが見つかりません", e.Resource) } func GetUser(id int) (string, error) { if id != 1 { return "", &NotFoundError{"ユーザー"} } return "スティーブ", nil } func main() { user, err := GetUser(2) if err != nil { if nfe, ok := err.(*NotFoundError); ok { fmt.Println(nfe.Resource, "の問題") } else { fmt.Println("エラー:", err) } } fmt.Println("ユーザー:", user) }
重要な特徴:
エラー処理で==で比較できるか、それとも特別なメソッドを使用する必要がありますか?
常にerrors.Is()を使用してエラーラッパーと比較することをお勧めします。そうしないと、エラーがラップされている場合に==による比較が機能しない可能性があります。
if errors.Is(err, os.ErrNotExist) { // ファイルの存在しない処理 }
カスタムエラーのために構造体タイプを実装する必要がありますか、それともerrors.New("...")を使うだけで十分ですか?
エラーメッセージだけが必要な場合は、errors.New()で十分です。コンテキスト(例えば、リソース名)を保持することが重要な場合は、Error()メソッドを持つstructを定義する方が良いでしょう。
関数が成功した場合、エラーをどのように正しく返すべきですか?
成功した場合は、常にnilをエラーとして返してください。
return result, nil
ネガティブケース
開発者が説明なしでエラーを返す関数を作成(単にerrors.New("失敗"))。ログを分析しても原因を特定できません。
利点:
欠点:
ポジティブケース
開発者がカスタムエラータイプNotFoundErrorを定義し、詳細な説明を添えて返す。
利点:
欠点: