2017-06-09 6 views
1

Go Specから:マップエントリが反復中に作成されている場合繰り返し処理中にマップに項目を追加すると、結果が一貫しないのはなぜですか?

、そのエントリは反復中に生成することができるか、スキップしてもよいです。

それでは、私はその文に期待することは、次のコードは、少なくともプリント枚数1、そして何より番号印刷しようとしている予測不可能であり、あなたがプログラムを実行するたびに異なっているべきであるということです。

package main 

import (
    "fmt" 
) 

func main() { 

    test := make(map[int]int) 

    test[1] = 1 
    j := 2 
    for i, v := range test { 
     fmt.Println(i, v) 
     test[j] = j 
     j++ 
    } 

    return 

} 

Go playground link

自分のラップトップ上で、それは8まで、遊び場(まだバージョン1.8)で、それはまさにまで3を印刷します印刷し、最大で(バージョン1.8を移動します)! 私はその移動がvanillaではないので、遊び場からの結果はあまり気にしませんが、なぜ私のローカルでは8以上を印刷しないのでしょうか?さらに私は、各反復でより多くのアイテムを追加しようとしましたが、8を上回る可能性を出す可能性はありますが、違いはありません。

EDITは:マップがmake機能でのみ1バケットが割り当てられている任意のサイズのパラメータを指定しないと、各バケットに行くに作成され@Schwernの答え

に基づいて自分自身の説明は、8の大きさを持っています要素が含まれているので、範囲が開始されると、マップに1つのバケットしかなく、最大8回反復されます。 make(map[int]int, 8)のように7より大きいサイズパラメータを使用すると、2つのバケットが作成され、追加されたアイテムに対して8回以上の反復が行われる可能性があります。

+1

私の推測では、 'test:= make(map [int] int)'は8つのキーと値のペアのためのスペースを持つマップを構築します。その後、Goは新しいループ配列を作成して、forループに格納されたコピーが使い果たされ、コードの実行がループを終了します。 –

+1

Go Playgroundは、そのランダム関数に固定の設定を使用することに注意してください。 – Schwern

答えて

1

これは、ほとんどのハッシュテーブルの設計に固有の問題です。ここでは、不必要な詳細を多く手に入れた簡単な説明があります。

フードの下では、ハッシュテーブルは配列です。各キーはhash functionを使用して配列内の要素にマップされます。たとえば、「foo」は要素8にマップされ、「bar」は要素4にマッピングされます。いくつかの要素は空です。

for k,v := range hashは、どのような順序でもこの配列を反復します。注文はcollision attackを避けるために予測できません。

ハッシュに追加すると、基本となる配列に追加されます。新しい大きな配列を割り当てる必要があるかもしれません。新しいキーがハッシュの配列にどこに置かれるかは予測できません。

ハッシュを繰り返している間にペアを追加すると、現在のインデックスより前に配列に配置されるペアは表示されません。その繰り返しはすでにその時点を過ぎています。 の後に置かれるものは、になる可能性があります。反復はまだその時点に達していますが、配列が再割り当てされ、ペアが再ハッシュされる可能性があります。

が、私は基本的な配列は、おそらく長さであるので、私のローカル上でそれ以上8

を印刷したことがない、なぜだろう8.ゴーはおそらく2のべき乗で根本的な配列を割り当て、おそらく開始します8時。range hashはおそらく基礎となる配列の長さをチェックすることから始まり、それが成長してもさらに進まないでしょう。

短いストーリー:反復処理中にハッシュにキーを追加しないでください。

+0

は私の答えを得ました: "基礎配列の長さはおそらく8であるため"、大きさパラメータが "7"より大きいmake関数のマップを作成すると、8個以上の項目を印刷し始めます。 – sepehr

関連する問題