実践Go言語(Effective Go)の翻訳、13回目です。
前回までの訳は実践Go言語[日本語訳]にまとめてあります。


エラー情報

ライブラリルーチンでは、呼び出し元にエラー情報などを返す必要が度々発生します。以前説明したように、Go言語の複数戻り値を使うと通常の戻り値と一緒にエラーの詳細情報を返すことが簡単にできます。またエラーは慣例的にos.Errorというシンプルなインタフェースを実装しています。

type Error interface {
    String() string
}

ライブラリの作成者はこのインタフェースと併せて、より高機能なモデルを自由に実装して構いません。こうすることでエラーを知らせるだけでなく、何らかの状況も提供することができます。この例として、os.Openは下のos.PathErrorを返しています。

// PathErrorは、エラーとそれを引き起こした操作及び
// ファイルパスが記録されます。
type PathError struct {
    Op string    // "open", "unlink", など
    Path string  // 関連ファイル
    Error Error  // システムコールからの戻り値
}

func (e *PathError) String() string {
    return e.Op + " " + e.Path + ": " + e.Error.String()
}

PathErrorStringメソッドは次のような文字列を生成します。

open /etc/passwx: no such file or directory

このようにエラー情報内に問題の起きたファイル名、操作、引き金となったオペレーティングシステムのエラーを含んでいると、エラーとなった呼び出し箇所から離れた箇所でエラー情報を出力したときにも役立ちます。「そのようなファイルやディレクトリはありません」と単に返されるより、多くの情報を与えてくれます。

呼び出し元で、エラーの正確な詳細情報が必要なときは、型スイッチまたは型アサーションを使い特定のエラーを探して詳細情報を得ることができます。たとえばPathErrorsの場合、内部のErrorフィールドを調べることでリカバリ可能か判断できることがあります。

for try := 0; try < 2; try++ {
    file, err = os.Open(filename, os.O_RDONLY, 0)
    if err == nil {
        return
    }
    if e, ok := err.(*os.PathError); ok && e.Error == os.ENOSPC {
        deleteTempFiles()  // 空き容量を回復
        continue
    }
    return
}