tour of go で学んだ Error() の定義と呼び方
問題 https://go-tour-jp.appspot.com/methods/20
検証コード Go Playground - The Go Programming Language
Error() の実行
Error() を実行させるためには、 error インタフェースを満たす値を fmt の print系の関数に渡してやる。
print系関数の中身では、渡された引数の error をチェックして not nil なら Error() を実行するような動きになるため。
// func ReturnErrFn() error {}
fmt.Println(ReturnErrFn())
「error インタフェースを満たす値」とは、Error() メソッドを呼び出せる型のこと。
func (e ErrNegativeSqrt) Error() string { return fmt.Sprintf("Err: ErrNegativeSqrt: %v", float64(e)) }
つまり、ある変数がこのメソッドを呼び出せるなら、その変数は error インタフェースを満たしている。(error インタフェースは Error() メソッドのみを実装しているため)
よってその変数を fmt の print系に渡せば、通常のprintではなく Error() が実行される。
Error() メソッドのレシーバは変数かポインタか?
ポインタレシーバにすると、呼び出し元の変数はポインタでなければならない。
func (e *ErrNegativeSqrt) Error() string { return fmt.Sprintf("Err: ErrNegativeSqrt: %v", float64(e)) } // ok fmt.Println(RetErr(&errNegativeSqrt)) // fail fmt.Println(RetErr(errNegativeSqrt))
対して変数レシーバの場合、呼び出し元は変数でもポインタでもどちらでもよい。
func (e ErrNegativeSqrt) Error() string { return fmt.Sprintf("Err: ErrNegativeSqrt: %v", float64(e)) } // ok fmt.Println(RetErr(&errNegativeSqrt)) // ok fmt.Println(RetErr(errNegativeSqrt))
有効な error インタフェース値の返却方法?
なんからの関数で error を返却する場合、エラーとなる書き方がある。
type ErrNegativeSqrt float64 func RetErr(x float64) error { // fail return &ErrNegativeSqrt(x) // fail var errNegativeSqrt *ErrNegativeSqrt = &(ErrNegativeSqrt(x)) return errNegativeSqrt // ok var errNegativeSqrt ErrNegativeSqrt = ErrNegativeSqrt(x) return &errNegativeSqrt // ok (error == nil なのでこれを print しても Error() は実行されない) var errNegativeSqrt *ErrNegativeSqrt return errNegativeSqrt }
一旦現在のスコープの変数にコピーしてからそのアドレスを返却する必要がありそう。
実行結果(右辺)のアドレスはその行が終了した時点でdropされて dangling pointer のようになっているのだろうか。。