A Tour of Goの練習問題を解説するシリーズ(6/11) – Exercise: Errors

みなさん、こんにちは。人類をGopherにしたいと考えているまるりんです。

A Tour of Goはプログラミング言語Goの入門サイトです。 このシリーズではA Tour of Goの練習問題を解説します。

今回は以下の問題を扱います。

問題
Exercise: Errors
解答
https://play.golang.org/p/QVe-kfX-4M6


問題に以下のように書かれているため、これらを脳死で記述します。

type ErrNegativeSqrt float64

ErrNegativeSqrt(-2).Error() で、 "cannot Sqrt negative number: -2" を返すような

func (e ErrNegativeSqrt) Error() string

最初に fmt.Sprint(float64(e)) として e を変換しておくことで、これを避けることができます。

負の値が与えられたとき、 ErrNegativeSqrt の値を返すように Sqrt 関数を修正してみてください。

ソース
https://play.golang.org/p/wlQPq5iPVCo

実行結果

./prog.go:11:37: cannot use ErrNegativeSqrt(x).Error() (type string) as type error in return argument:
    string does not implement error (missing Error method)

コンパイルエラーです。よくみたらerrorはインタフェースでした。

error interface {
    Error() string
}

ErrNegativeSqrtError()を実装しているため、この型を直接返せば良いことが分かります。 つまり、型ErrNegativeSqrtError()を実装(インタフェースを満た)しているのでインタフェースerrorに代入可能です。

ソース
https://play.golang.org/p/_2UYgLReXVr

実行結果

0 <nil>
-2 cannot Sqrt negative number: -2

入力が負の値の場合Error()関数を通るようになりました。 このプログラムに以前作ったSqrt()関数を移植すればプログラム完成です。

ソース
https://play.golang.org/p/QVe-kfX-4M6

実行結果

1.414213562373095 <nil>
-2 cannot Sqrt negative number: -2

最後に注意にある「なぜでしょうか?」に答えます。

注意: Error メソッドの中で、 fmt.Sprint(e) を呼び出すことは、無限ループのプログラムになることでしょう。 最初に fmt.Sprint(float64(e)) として e を変換しておくことで、これを避けることができます。 なぜでしょうか?

前ページに以下のように書かれています。

fmt.Stringer と同様に、 fmt パッケージは、変数を文字列で出力する際に error インタフェースを確認します。

変数eの型はErrNegativeSqrtです。eはerrorインタフェースを満たす関数Error()を実装しています。 Error()内のfmt.Sprint(e)がeを評価する際にe.Error()を呼び出します。このe.Error()は型ErrNegativeSqrtが実装しているError()なので再度Error()が呼び出されてfmt.Sprint(e)が評価されます。 このようにError()の再帰呼び出しが無限に続いてしまいます。これを避けるためにfmt.Sprint(float64(e))を使用してeの型をErrNegativeSqrtからstringに変換しています。

インタフェースに対する理解がさらに深まりました。