Значение хеша по умолчанию не используется

Сегодня я попробовал следующие фрагменты кода, и я не понимаю, почему я получаю разные результаты между ними. Насколько я понимаю, они одинаковые.

Один использует значение по умолчанию off Hash, а другой фрагмент создает пустой массив для ключа, прежде чем он будет доступен.

Кто-нибудь понимает, что происходит? :)

# Hash default if the key doesn't have a value set is an empty Array
a = Hash.new([])
a[:key] << 2 # => [2]
p a # => {} nil
p a[:key] # => [2]
p a.keys # => []
p a.values # => []

# Explicitly add an array for all nodes before creating
b = Hash.new
b[:key] ||= []
b[:key] << 2 # => [2]
p b # => {:key=>[2]}
p b.keys # => [:key]

Руби версии 1.8.7


person gaqzi    schedule 22.04.2010    source источник
comment
У меня был тот же вопрос некоторое время назад: stackoverflow.com/questions/2552579/   -  person Mladen Jablanović    schedule 22.04.2010
comment
Я не думаю, что они одинаковы. Если я попробую это с блоком, как вы, я не увижу значение, которое я ввел с помощью p a[:key]. Но поскольку по умолчанию это не блок, я получаю значение, но оно не отображается, пока я не вызову конкретный ключ. С a.keys или a.value я получаю пустой Array обратно. Похоже на способ добавить секретные ключи к Hash, по какой-то причине это было бы хорошо.   -  person gaqzi    schedule 22.04.2010
comment
Извините, не совсем то же самое. Вы изменили значение по умолчанию (попробуйте напечатать a[:foo] в первом примере, и вы увидите). Я всегда начинаю с пустого массива. Кстати, я спрашивал также об этом, кажется, еще более похожим: хешировать новые скрыть хеш-члены"> stackoverflow.com/questions/1822021/   -  person Mladen Jablanović    schedule 22.04.2010


Ответы (2)


Когда вы сделали a[:key] << 2, вы убрали это значение по умолчанию пустого массива и добавили к нему 2 (изменив фактический массив, а не ссылку), не сообщая хеш-объекту a, что вы что-то изменили. Вы изменили объект, который a использовал по умолчанию, поэтому вы также увидите это:

p a[:wat] #=> [2]
p a[:anything] #=> [2]

Во втором примере вы создали новый массив и используете b[:key]=, который сообщает b, что у него есть значение под этим ключом.

Попробуйте это, если вы хотите получить лучшее из обоих миров:

c = Hash.new([])
c[:key] += [2]

Это позволит получить доступ к c[:key] и создать новый массив с + и переназначить его.

person mckeed    schedule 22.04.2010

Возможно, это поможет:

a = Hash.new { |hash, key| hash[key] = [] }
a[:key] << 2 # => [2]
a[:key]      # => [2]
p a          # => {:key=>[2]}
person maček    schedule 22.04.2010