2

重複の可能性:
RubyメソッドArray#<<ハッシュで配列を更新しない
Hash.new([])を使用する場合の奇妙なrubyの動作

私は素晴らしいKoansをやっています、そして私が進むにつれて私は大きな問題を見つけません、しかし私はこれに遭遇しました、そしてそれから何の意味もありません:

    def test_default_value_is_the_same_object
        hash = Hash.new([])

        hash[:one] << "uno"
        hash[:two] << "dos"

        assert_equal ["uno", "dos"], hash[:one]   # But I only put "uno" for this key!
        assert_equal ["uno", "dos"], hash[:two]   # But I only put "dos" for this key!
        assert_equal ["uno", "dos"], hash[:three] # I didn't shove anything for :three!

        assert_equal true, hash[:one].object_id == hash[:two].object_id 
    end

すべてのテストに合格しています(書き込みに適切なアサーションを推測するのに役立つエラーを確認しました)。

最後のアサーション、わかりました。どちらも初期化されていないため、両方ともデフォルトを使用するため、値は同じオブジェクトIDを持つ必要があります。

デフォルト値が変更された理由がわかりません。それが何が起こったのか完全にはわかりません。

IRBで試してみましたが、ハッシュ/配列を改ざんして気が狂ったのではないかと思いましたが、同じ結果が得られました。

私は最初になるhash[:one] << "uno"ことを意味すると思いましたが、それは残っています。呼び出しだけ だと思いますが、新しいキーはサインを使用した場合にのみ追加されますhash{ one: ["uno] }{ }
<<push=

見逃したことを教えてください。

編集:私はRuby1.9.3を使用しています

4

2 に答える 2

3

ハッシュにデフォルトの引数を使用すると、明示的に設定されていないすべてのキーに同じオブジェクトが使用されます。これは、ここで使用されているのは、渡した配列の1つHash.newだけであることを意味します。その証拠については、以下を参照してください。

>> h = Hash.new([])
=> {}
>> h[:foo] << :bar
=> [:bar]
>> h[:bar] << :baz
=> [:bar, :baz]
>> h[:foo].object_id
=> 2177177000
>> h[:bar].object_id
=> 2177177000

奇妙なことに、あなたが見つけたように、ハッシュを調べると、それが空であることがわかります!これは、デフォルトオブジェクトのみが変更されており、キーがまだ割り当てられていないためです。

幸い、ハッシュのデフォルト値を実行する別の方法があります。代わりに、デフォルトのブロックを指定できます。

>> h = Hash.new { |h,k| h[k] = [] }
=> {}
>> h[:foo] << :bar
=> [:bar]
>> h[:bar] << :baz
=> [:baz]
>> h[:foo].object_id
=> 2176949560
>> h[:bar].object_id
=> 2176921940

このアプローチを使用すると、割り当てられていないキーが使用されるたびにブロックが実行され、ハッシュ自体とキーが引数として提供されます。ブロック内でデフォルト値を割り当てることにより、個別のキーごとに新しいオブジェクトが作成され、割り当てが自動的に行われるようにすることができます。これは、Rubyで「配列のハッシュ」を作成する慣用的な方法であり、通常、デフォルトの引数アプローチよりも安全に使用できます。

とはいえ、不変の値(数値など)を使用しているHash.new(0)場合は、再割り当てによってのみこれらの値を変更するため、のようなことを行うのは安全です。しかし、頭の中にある概念を少なくしたいので、私はほとんどブロック形式を排他的に使用します。

于 2012-11-11T23:24:03.663 に答える
1

あなたがするとき

h = Hash.new(0)
h[:foo] += 1

直接変更していhます。h[:foo] += 1と同じh[:foo] = h[:foo]+1です。h[:foo]割り当てられてい0+1ます。

あなたがするとき

h = Hash.new([])
h[:foo] << :bar

のデフォルト値ですが、のどのキーの値でもない、を変更h[:foo]しています。その後、のデフォルト値はになりますが、それはの値ではありません。[]hh[][:bar]h[:bar]h[:foo]

于 2012-11-11T23:17:37.583 に答える