質問: ``` a := []int{} b := [...]int{} c := []int(nil) var d []int ``` 上記の変数`a`~`d`はいずれも「要素数0のint型配列」を表していますが、`reflect.DeepEqual`で比較してみると、すべてが同じ値というわけではないように見えました。 `[]int`と`[0]int`型が区別されるのは(SliceとArrayの違いなので)ぼんやりと理解できますが、そうすると同じ型のはずの`[]int{}`と`[]int(nil)`(`a`と`c`)が区別されるのが腑に落ちません。 これらの型はどう区別、比較すればいいのでしょうか? 例えば、配列を返す関数をテストしたい場合に、返り値が空配列となるケースをどのようにテストすればいいのか知りたいです。
回答: 個人的には、そのまま、`reflect.DeepEqual`を使うのが良いと思います。 問題は、「空配列」が何か、ということです。ご存知のとおり、Goにはスライスとarrayというよく似た別のものがあります。この2つは型のレベルで等しくありません。`a`と`b`がdeeply equalでない理由がこれです1。 `reflect.DeepEqual`のgodocには次のように書かれています。 > > Slice values are deeply equal when all of the following are true: they are both nil or both non-nil, they have the same length, and either they point to the same initial entry of the same underlying array (that is, &x[0] == &y[0]) or their corresponding elements (up to length) are deeply equal. Note that a non-nil empty slice and a nil slice (for example, []byte{} and []byte(nil)) are not deeply equal. > > > 変数`a`と`c`の違いは、nilかどうかです1。ドキュメントに書かれているように、non-nilな空のスライス`a`は、nilスライス`c`とdeeply equalではありません。したがって`reflect.DeepEqual(a, c)`はfalseを返します。 最後に、変数`d`は、[]int 型のnilです1。したがって`c`とdeeply equalになります。 つまり、`a`から`d`までの変数の中で、空の(non-nilな)スライスは`a`だけ、空の(non-nilな)arrayは`b`だけということになります。 今回の場合、テストに用いたいということですので、nilかnilでないか、スライスかarrayかは、大きな違いになると思います。したがって、そのまま`reflect.DeepEqual`を使って、厳密にどれになるのかを検査するのが良いのではないかと思います。 ちなみに`a`から`d`までのすべてをOKとしたいのであれば、(スライスかarrayしか返ってこないと分かっているときは) `len(変数) == 0` かどうかを調べれば良いです2。interface{}な値について調べたいのであれば、たとえば型switchを併用する方法があると思います( )。metropolisさんのコメントも参考になるかと思います。 また、]int 型ではなく []byte 型に限った話をすると、 `bytes.Equal`([godoc)という便利なものがあります。この関数ではnilと空スライスが同一視されます。残念ながら現状(go1.7では)アセンブリで実装されているため、他の型に対してこの関数の実装と同じ方法を使うのは簡単ではないでしょう。 註 1. 各変数がどのような型と値になっているのかについて詳細に書きます。 * `a`、つまり`]int{}`は、[]int 型のnon-nilな長さ0のsliceです。このことは仕様の ["Composite literals" などから分かります。 * `b`、つまり`...]int{}`は [0]int 型のarrayです。この書き方の分かりにくいところは`[...]`の部分なのではないかと思います。これはたとえば`[...]int{2, 4, 6}`のようなリテラルを書くときに、わざわざ`[3]int{2, 4, 6}`と書きたくがないための記法です。今回は要素の無い列に対してこの記法を使っていることになり、`[0]int{}`とほぼ同じことです。このことは`a`と同じく仕様の ["Composite literals" などから分かります。 * `c`、つまり`]int(nil)`は、[]int 型のnilです。こちらは仕様の ["Conversions" などから分かります。したがって厳密には`c`は「空配列」ないし「空スライス」では無いです。 * `d`は、]int 型として宣言され、初期化されていない変数です。Goでは初期化されていないsliceの値が nil になるため、`d`は []int 型のnilです。このことは仕様の ["The zero value" から分かります。 2. `len(nil)`は必ず0です。"Length and capacity" に書いてあります。