dup дает разные результаты, когда хеш равен одному или двум измерениям

dup это мелкая копия, поэтому при этом:

h = {one: {a:'a', b: 'b'}}
h_copy = h.dup
h_copy[:one][:b] = 'new b'

сейчас h а также h_copy такой же: {:one=>{:a=>"a", :b=>"new b"}}Да, это правильно.

Но когда h это одномерный хеш:

h = {a:'a', b: 'b'}
h_copy = h.dup
h_copy[:b] = 'new b'
h still is: {a:'a', b: 'b'}
h_copy is {a:'a', b: 'new b'}

Зачем?

3 ответа

Решение

Итак, после 1 часа мозгового штурма. Я пришел к выводу, что в многомерных хешах dup генерирует один и тот же object_id для каждого ключа, который, в свою очередь, ссылается на хеш, тогда как в одномерном хеше object_ids изначально похожи но когда мы вносим какие-либо изменения в объект, Ruby назначает новый object_id хеш-ключам.

Посмотрите на следующий код

h = { :a => "a", :b => "b" } # => {:a=>"a", :b=>"b"} 
h_clone = h.dup #=> {:a=>"a", :b=>"b"} 
h.object_id #=> 73436330 
h_clone.object_id #=> 73295920 
h[:a].object_id #=> 73436400 
h_clone[:a].object_id #=> 73436400 
h[:b].object_id #=> 73436380 
h_clone[:b].object_id #=> 73436380 
h_clone[:b] = "New B" #=> "New B" 
h_clone[:b].object_id #=> 74385280 
h.object_id #=> 73436330 
h_clone.object_id #=> 73295920 
h[:a].object_id #=> 73436400 
h_clone[:a].object_id #=> 73436400

Посмотрите следующий код для многомерного массива

h = { :one => { :a => "a", :b => "b" } } #=> {:one=>{:a=>"a", :b=>"b"}} 
h_copy = h.dup #=> {:one=>{:a=>"a", :b=>"b"}} 
h_copy.object_id #=> 80410620 
h.object_id #=> 80552610 
h[:one].object_id #=> 80552620 
h_copy[:one].object_id #=> 80552620 
h[:one][:a].object_id #=> 80552740 
h_copy[:one][:a].object_id #=> 80552740 
h[:one][:b].object_id #=> 80552700 
h_copy[:one][:b].object_id #=> 80552700 
h_copy[:one][:b] = "New B" #=> "New B" 
h_copy #=> {:one=>{:a=>"a", :b=>"New B"}} 
h #=> {:one=>{:a=>"a", :b=>"New B"}} 
h.object_id #=> 80552610 
h_copy.object_id #=> 80410620 
h[:one].object_id #=> 80552620 
h_copy[:one].object_id #=> 80552620 
h[:one][:b].object_id #=> 81558770 
h_copy[:one][:b].object_id #=> 81558770

Вы можете думать о своем двумерном хеше как о некоем контейнере, который содержит другой хеш-контейнер. Итак, у вас есть 2 контейнера.

Когда вы звоните dup на h, затем dup возвращает вам копию вашего самого внешнего контейнера, но любые внутренние контейнеры не копируются, так что это то, что делает мелкая копия. Теперь после dup у вас есть 3 контейнера: h_copy ваш новый третий контейнер, который :one ключ просто указывает на hвнутренний контейнер

Как вы сказали, dup это мелкая копия.

Похоже, вы хотите оба h_copy а также h ссылаться на тот же объект.

Тогда просто делай h_copy = h (т.е. нет dup).

h = {a:'a', b: 'b'}
h_copy = h.dup
h_copy[:b] = 'new b'
h #=> {a:'a', b: 'new b'}
Другие вопросы по тегам