Go のスライス比較の落とし穴

Go にはスライスを比較する演算子が存在しない。「同一のスライス」を「同じキーとバリューを過不足なく持つこと」と定義して、スライス s1s2 が同一かどうかを判定する関数を書いてみよう。

スライス比較のありがちなミス

次の実装にはバグがある。

この関数に次の値を与えると true が返る。

s1 := map[string]int{"a": 0}
s2 := map[string]int{"b": 1}
fmt.Println(equalBad(s1, s2))

s2["a"] が 0 だからだ。s2 にキー "a" は存在しない。だから s2["a"]intゼロ値を返す。int のゼロ値は 0 だ。

スライス s1s2 を正しく比較するには、s1 のキーが s2 に存在することも確認しなければならない。

ゼロ値を含めた比較

次のようにスライス比較を実装すればよい。

if v2, ok := s2[k]; !ok || v2 != v1 { ... }

この記述はイディオムに近い。 oks2[k] がゼロ値でないときに true になる。

まとめ

単純で間違いやすいスライスの比較について取り上げた。Go ではゼロ値を意識しないと容易にバグを埋め込んでしまう。注意が必要だ。

単体で動作する実験コードを貼っておく。

コメントを残す

コメントを投稿するには、以下のいずれかでログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中