A Tour of Goの練習問題を解説するシリーズ(6/11) – Exercise: Errors
みなさん、こんにちは。人類をGopherにしたいと考えているまるりんです。
A Tour of Goはプログラミング言語Goの入門サイトです。 このシリーズではA Tour of Goの練習問題を解説します。
今回は以下の問題を扱います。
問題
Exercise: Errors
解答
https://go.dev/play/p/lrgdnOYm85X
問題に以下のように書かれているため、これらを脳死で記述します。
type ErrNegativeSqrt float64
ErrNegativeSqrt(-2).Error() で、 "cannot Sqrt negative number: -2" を返すような
func (e ErrNegativeSqrt) Error() string
最初に fmt.Sprint(float64(e)) として e を変換しておくことで、これを避けることができます。
負の値が与えられたとき、 ErrNegativeSqrt の値を返すように Sqrt 関数を修正してみてください。
ソース
https://go.dev/play/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
}
型ErrNegativeSqrt
はError()
を実装しているため、この型でキャストした値を返せば良いことが分かります。
つまり、型ErrNegativeSqrt
はError()
を実装(インタフェースを満た)しているので実体をインタフェースerror
に代入可能です。
ソース
https://go.dev/play/p/_2UYgLReXVr
実行結果
0 <nil>
-2 cannot Sqrt negative number: -2
入力が負の値の場合Error()
関数を通るようになりました。
このプログラムに以前作ったSqrt()関数を移植すればプログラム完成です。
型変換したeの値を直接fmt.Sprintf()
に渡すように変更しました。
ソース
https://go.dev/play/p/lrgdnOYm85X
実行結果
1.414213562373095 <nil>
-2 cannot Sqrt negative number: -2
最後に問題文の注意にある「なぜでしょうか?」に答えます。
注意: Error メソッドの中で、 fmt.Sprint(e) を呼び出すことは、無限ループのプログラムになることでしょう。 最初に fmt.Sprint(float64(e)) として e を変換しておくことで、これを避けることができます。 なぜでしょうか?
前ページに以下のように書かれています。
fmt.Stringer と同様に、 fmt パッケージは、変数を文字列で出力する際に error インタフェースを確認します。
変数eの型はErrNegativeSqrt
です。型ErrNegativeSqrt
はerrorインタフェースを満たす関数Error()
を実装しています。
ErrNegativeSqrt.Error()
でfmt.Sprint(e)
を呼び出すと、fmt.Sprint()
処理内で引数eのe.Error()
を呼び出します。このe.Error()
はErrNegativeSqrt.Error()
です。そのため再びfmt.Sprint(e)
が評価されます。
このようにErrNegativeSqrt.Error()
の呼び出しが無限に続いてしまいます。これを避けるためにfloat64(e)
を使用してeの型をErrNegativeSqrt
からfloat64
に変換しています。
インタフェースに対する理解がさらに深まりました。