Go by Example: Errors

Go では、エラーを明示的な、別の戻り値として扱うのが特徴です。 これは、Java や Ruby のような言語で使われる例外や、 C で時々使われる結果/エラーを多重定義した単一の値とは 対照的です。 Go のアプローチは、どの関数がエラーを返したかを調べやすくし、 エラー以外のほかのタスクに使うのと同じ言語機能でエラーも 扱えるようにします。

package main
import (
    "errors"
    "fmt"
)

慣例的に、エラーは戻り値の最後にし、 組み込みインターフェースである error 型をもちます。

func f1(arg int) (int, error) {
    if arg == 42 {

errors.New は、与えられたエラーメッセージをもつ 基本的な error 値を作ります。

        return -1, errors.New("can't work with 42")
    }

エラーに対する nil 値は、エラーがなかったことを示します。

    return arg + 3, nil
}

Error() メソッドを実装することで、独自の型を error として使うことができます。次の例は、 明示的に引数エラーを表現する独自の型を使って、 上のサンプルコードを書き換えたものです。

type argError struct {
    arg  int
    prob string
}
func (e *argError) Error() string {
    return fmt.Sprintf("%d - %s", e.arg, e.prob)
}
func f2(arg int) (int, error) {
    if arg == 42 {

この場合、新しい構造体を作るために &argError という構文を使って、 argprob の 2 つのフィールドに値を設定しています。

        return -1, &argError{arg, "can't work with it"}
    }
    return arg + 3, nil
}
func main() {

次の 2 つのループは、先のエラーを返す各関数を試します。 この if を使ったインラインのエラーチェックは、Go コードの一般的なイディオムであることに注意してください。

    for _, i := range []int{7, 42} {
        if r, e := f1(i); e != nil {
            fmt.Println("f1 failed:", e)
        } else {
            fmt.Println("f1 worked:", r)
        }
    }
    for _, i := range []int{7, 42} {
        if r, e := f2(i); e != nil {
            fmt.Println("f2 failed:", e)
        } else {
            fmt.Println("f2 worked:", r)
        }
    }

もし独自エラーのデータをプログラムで使いたければ、 型アサーション (type assertion) を使って、 独自エラー型のインスタンスとしてエラーを取得する 必要があるでしょう。

    _, e := f2(42)
    if ae, ok := e.(*argError); ok {
        fmt.Println(ae.arg)
        fmt.Println(ae.prob)
    }
}
$ go run errors.go
f1 worked: 10
f1 failed: can't work with 42
f2 worked: 10
f2 failed: 42 - can't work with it
42
can't work with it

エラーハンドリングのさらなる情報については、Go ブログのこの 素晴らしい記事 を参考にしてください。

Next example: Goroutines.