Go言語で当たり前に扱っているnil。他の言語でいうnullと同じだと思っていませんか?
実は明確に違いがあります。
今回はそんなGo言語のnilについて深掘って説明していきます。
Go言語のnilとは? 他言語のnullとの違い
nil(ニル)はGoで事前に定義された識別子で、ポインタ、インターフェイス、マップ、スライス、チャネル、関数型などのゼロ値を表します。
ゼロ値とは初期化されていない値のことです。
nilは何らかの「未定義」な状態を意味するのではなく、それ自体が値です。Goのオブジェクトがnilであるとはシンプルにその値がnilであることを意味します。
nilは他の言語のnull(またはNULL)と同じものと考えられがちです。でも実際には違います。
例えばPHPやJavaのnullは値が存在しないことを示す特殊な値であり型がありません。しかしGo言語でのnilは値が存在しないことを示すだけでなく型を持っています。
例えば、以下のコードではxとyはともにnilですが型が異なります。
var x *int // ポインタ型の変数xはnil
var y interface{} // インターフェース型の変数yはnil
fmt.Println(x == y) // false
参照型のオブジェクトがnilである場合の意味
nilはポインタやインターフェースなどの「参照」型の変数に対しては、その変数が他の型のインスタンスを参照していないことを示します。
以下のサンプルコードでは、sとpはともにnilですがsは空のスライスを表しpは空のポインタを表します。
var s []int // スライス型の変数sはnil
var p *int // ポインタ型の変数pはnil
fmt.Println(s == nil) // true
fmt.Println(p == nil) // true
エラー型の場合のnil
nilはエラー型の変数に対してエラーが発生していないことを示します。
エラー型は、実は単なるインターフェイス型の一種で、このように定義されています。
type error interface {
Error() string
}
エラー型の変数がnilであるとはその変数がerrorインターフェイスを実装する型のインスタンスを参照していないということです。
いつものようにやっているエラーハンドリングのコードはerrがnilだとそれはエラーが発生していないことを意味しますよね。
この変数err がerrorインターフェイスを参照していなんですね。
n, err := fmt.Println("Hello, world!") // nは出力したバイト数、errはエラー
fmt.Println(err == nil) // true
以上、nilについて少しだけ細かい説明をしてみました。