絶対ハマるらしいgolangのnilにハマった件

ハマりましたwwww

func main() {
    var e1 error
    e1 = x()
    if e1 == nil {
        fmt.Printf("e1 == nil: %v\n", e1)
    } else {
        fmt.Printf("e1 != nil: %v\n", e1)
    }

    var e2 *NyanError
    e2 = x()
    if e2 == nil {
        fmt.Printf("e2 == nil: %v\n", e2)
    } else {
        fmt.Printf("e2 != nil: %v\n", e2)
    }
}

func x() *NyanError {
    return nil
}

// エラー
type NyanError struct {
}

func (e *NyanError) Error() string {
    return "にゃー"
}

出力

e1 != nil: にゃー
e2 == nil: にゃー

どゆこと?

https://play.golang.org/p/z5pdAdI0YZ

正直go書き始めて3日程度の俺にはよくわからんのだが、errorのようなinterface型の変数は、実行時にnilが渡されたとしても渡されるであろう構造体の型情報を保持しているらしい。んで、この型情報も一致しないと == nil にならないらしいマジすか。nilリテラルは値がnilで型もnilだが、e1は値がnilで型がNyanError、なので不一致。

値はnilなのに、 fmt.Printf(“%v”, e1) で “にゃー” とか表示されるのは変数が型情報を持っているからなんすね…

interface型変数の場合 e == nil || reflect.ValueOf(e).IsNil() と判定するといいらしい。これは、変数の型情報を無くして値だけで比較する方法って事ですか。

しかし、変数の型が構造体型かinterface型かで動き変わるなんて思わんかったよw