1. エラーハンドリングの基本
まず、基本的なエラーハンドリングの例を見てみましょう。ここでは、ファイルを開いて読み込むというシンプルなタスクを考えます。
file, err := os.Open("example.txt")
if err != nil {
log.Fatalf("failed opening file: %s", err)
}
defer file.Close()
byteSlice := make([]byte, file.Stat().Size())
_, err = file.Read(byteSlice)
if err != nil {
log.Fatalf("failed reading file: %s", err)
}
fmt.Printf("file content: %s", byteSlice)
ここでは、 os.Open
から返されたエラーを確認し、エラーが存在する場合にはログメッセージを出力してプログラムを終了しています。また、 file.Read
から返されたエラーも同様に確認しています。
2. エラーラッピング
次に、エラーラッピングについて見てみましょう。エラーラッピングは、エラーの原因を追跡しやすくするための重要なテクニックです。
func doSomething() error {
err := doAnotherThing()
if err != nil {
return fmt.Errorf("doAnotherThing failed: %w", err)
}
return nil
}
ここでは、 doAnotherThing
関数から返されたエラーをラップしています。ラップされたエラーは、元のエラーメッセージに追加のコンテキストを提供します。
3. カスタムエラー
より詳細なエラー情報を提供するために、カスタムエラーを定義することも可能です。以下の例では、特定の状況で発生する可能性のあるエラーのためにカスタムエラーを定義しています。
type NotFoundError struct {
FileName string
}
func (e *NotFoundError) Error() string {
return fmt.Sprintf("file not found: %s", e.FileName)
}
func readFile(fileName string) ([]byte, error) {
file, err := os.Open(fileName)
if os.IsNotExist(err) {
return nil, &NotFoundError{FileName: fileName}
} else if err != nil {
return nil, err
}
defer file.Close()
// ファイルの読み込み処理...
}
ここでは、 NotFoundError
というカスタムエラーを定義し、ファイルが存在しない場合にこのエラーを返すようにしています。このようなカスタムエラーを使用すると、エラーが発生した具体的な状況をより詳細に表現することができます。