2016-06-18 17 views
1

Goのスライス(Go配列の実装)をGoマップのキーとして使用できないのはなぜですか。配列はキーとして使用できますか?ここでGoのスライスをGoマップのキーとして使用できないのは、配列をキーとして使用するのと同じですか?

+2

スライスの平等性を比較できますか?いいえの場合は、それを使用することはできません。または、等価比較のない型をマップ内のキーとして使用することはできません。 – Arunmu

答えて

3

https://groups.google.com/forum/#!topic/golang-nuts/zYlx6sR4F8Yからのナイジェル・タオの答えです:

一つの理由は、配列は値型であるということです。 a0[N]int( 配列)であれば、

a1 := a0 
a1[0] = 0 

を行うことは全くa0[0]には影響しません。

これに対して、スライスは、基本となる配列を参照しています。スライス の値をコピーすると、O(長さ)ではなくO(1)になります。 s0[]int(スライス) であれば、

s1 := s0 
s1[0] = 0 

を行うと、s0[0]が何であるかに影響します。

http://play.golang.org/p/TVkntIsLo8

地図キーは平等のいくつかの概念を必要とします。配列の場合、これは単純に 要素同値です。スライスの場合、 は等価を定義する複数の方法があります.1つは要素ごとの等価、もう1つは と同じ配列のバッキングストアです。さらに、地図の挿入は にする必要がありますか?バッキングアレイ全体の(高価な)コピーを作成しますか? のコピーはおそらくあまり驚くことではありませんが、それは の割り当てと矛盾しています。

このコードスニペットはどのように印刷する必要がありますか?

m := make(map[[]int]bool) 
s0 := []int{6, 7, 8} 
s1 := []int{6, 7, 8} 
s2 := s0 
m[s0] = true 
s2[0] = 9 
println(m[s0]) 
println(m[s1]) 
println(m[s2]) 

異なるプログラマは、異なる期待を持つことができます。 の混乱を避けるため、今度は の地図キーとしてスライスを許可しないことにしました。

2

正確に答えるために:

Spec: Map types:

comparison operators ==と=完全にキータイプのオペランドに定義する必要があります。 "なぜカントの?"!したがって、のキータイプは、の関数、マップ、またはスライスであってはなりません。

この仕様では、比較が定義されていないキータイプは許可されません。

スライス、マップ、および関数の値は、比較できないです:Spec: Comparison operatorsもこれを確認しました。

推論のために、smarxの答え(引用符はNigel Tao's answer)を参照してください。そして読んでください。

Goのマップはhashmapの実装を使用しています。一般に(プログラミング言語に関係なく)、ハッシュマップでキーとして使用される値を変更すると、未定義(または予期しない最小の)動作が発生する可能性があります。通常、キーのハッシュコードは、値(キーと値のペア)が配置されているバケットを指定するために使用されます。キーが変更され、そのキーに関連付けられた値を要求すると、実装は間違ったバケットを検索する可能性があります(したがって、見つからないことを報告する)。変更されたキー値は、異なるバケツ。

Goスライスは、基本となる配列の連続する部分の記述子であり、スライス値を割り当てるとこれらの記述子のみがコピーされます。したがって、スライスをキーとして使用すると、マップ実装はこのスライスヘッダー(基本配列の最初に参照される要素へのポインタ、長さ、および容量)のみをコピーすることが期待されます。ハッシュコンパイルと平等がこれらの3つの要素と他のものを使用する場合にのみ機能しますが、私たち(人間、プログラマー)にとって、スライスはスライスヘッダーを通じてアクセスできる要素を意味します - 変更することもできます)。

マップでスライスがキーとして機能するようにするには、適切に機能するために、スライス(キーとして使用される)のスライス要素が変更されるたびに内部状態とデータ構造を更新する必要があります予想された。

アレイはこの点でクールです。配列はすべての要素を意味します。配列をコピーするとすべての要素がコピーされ、比較は次のように定義されます。

配列要素の型の値が匹敵する場合、配列の値は匹敵します。対応する要素が等しい場合、2つの配列値は等しいです。

そして、あなたが前にキーとして使用される配列の要素を変更する場合(その改変体を有する)新しいアレイマップに格納され、使用される元に等しくないようにしない問題変更された配列で関連付けられた値を照会すると、結果が得られず、変更されていない元の配列で照会すると、以前に保管された値が正しく戻されます。

関連する問題