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'}