Goで複数のデータをひとまとめに格納する方法として、スライスがあります。概ね他言語の配列と同様ですが、型を持ちます。
Go の空スライスには、要素数が 0 の「ゼロ長スライス」と、そもそも初期化されていないnil
スライスの2種類があります。この2つについては良く似ていますが区別しないとエラーの原因になるため、意識して判別する必要があります。
var a []int // nil スライス
b := []int{} // ゼロ長スライス(非 nil)
c := make([]int, 0) // ゼロ長スライス(非 nil)
fmt.Println(a == nil, len(a)) // true 0
fmt.Println(b == nil, len(b)) // false 0
fmt.Println(c == nil, len(c)) // false 0
* `len(s) == 0` … 要素数が 0
* `s == nil` … スライス自体が初期化されていない
このように、要素数の取得、およびnilとの比較によってそれぞれを判定できます。
「要素はないけれど、明示的にゼロ長スライスとして生成されたもの」だけを取り出したい場合は、両方の条件を組み合わせる必要があります。
s := make([]int, 0) // 空だが nil ではないスライス
if len(s) == 0 && s != nil {
fmt.Println("スライスは空だが nil ではありません")
} else if s == nil {
fmt.Println("スライスは nil です")
} else {
fmt.Println("スライスには要素があります")
}
// `len(s) == 0` … 要素数が 0
// `s != nil` … nil スライスではない
まとめ
– nil
スライス:宣言のみで初期化されていない
– ゼロ長スライス:要素数が 0 だが、[]T{}
や make
で生成される
– 空かどうか:len(s) == 0
– nil かどうか:s == nil
– 空かつ非 nil:len(s) == 0 && s != nil
len+比較演算子で判定しなければならなかったり、「空かつ非nil」のシンプルな判定方法が無いのは少し冗長で残念な気もしますが、Goの流儀としてそういう仕様や組み込み関数は実装しない傾向にあるようです。こういうものとして納得しましょう。
参考
A Tour of Go
https://go.dev/tour/moretypes/7