Почему в Ruby Array.new (размер, объект) создает массив, состоящий из нескольких ссылок на один и тот же объект? - PullRequest
5 голосов
/ 10 января 2011

Как уже упоминалось в , этот ответ , Array.new(size, object) создает массив с size ссылками на те же object.

hash = Hash.new
a = Array.new(2, hash)
a[0]['cat'] = 'feline'
a # => [{"cat"=>"feline"},{"cat"=>"feline"}]
a[1]['cat'] = 'Felix'
a # => [{"cat"=>"Felix"},{"cat"=>"Felix"}]

Почему Ruby делает это, а не dup или clone из object?

Ответы [ 3 ]

9 голосов
/ 10 января 2011

Потому что это то, что документация говорит, что делает.Обратите внимание, что Hash.new вызывается только один раз, поэтому, конечно, есть только один Hash

Если вы хотите создать новый объект для каждого элемента в массиве, передайте блок методу Array.newи этот блок будет вызываться для каждого нового элемента:

>> a = Array.new(2) { Hash.new }
=> [{}, {}]
>> a[0]['cat'] = 'feline'
=> "feline"
>> a
=> [{"cat"=>"feline"}, {}]
>> a[1]['cat'] = 'Felix'
=> "Felix"
>> a
=> [{"cat"=>"feline"}, {"cat"=>"Felix"}]
2 голосов
/ 10 января 2011

Для некоторых классов, которые нельзя изменить на месте (например, Fixnum s), форма Array.new(X, object) работает, как ожидается, и, вероятно, более эффективна (просто вызывает memfill вместо rb_ary_store и yield в блок):

Для более сложных объектов у вас всегда есть блочная форма (например, Array.new(5) { Hash.new }).

* Редактировать : * Изменено в соответствии с комментариями. Извините за глупый пример, я устал, когда написал это.

0 голосов
/ 27 ноября 2018

Я придумал этот ответ, очень короткое и простое решение

c_hash = Hash.new
["a","b","c","d","e","f"].each do |o|
  tmp = Hash.new
  [1,2,3].map {|r| tmp[r] = Array.new}
  c_hash[o] = tmp
end
c_hash['a'][1] << 10
p c_hash
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...