Подтвердить что ты не робот

Почему Hash.new({}) скрывает элементы хэша?

Хорошо, поэтому я хотел создать хэш, который имеет пустой хеш в качестве значения по умолчанию. Немного странно, я знаю, но позвольте сказать, что я думал, что это может быть полезно.

Итак, вот что я сделал:

>> a = Hash.new({})
=> {}
>> a[:a][:b] = 5
=> 5
>> a
=> {}
>> a[:a]
=> {:b=>5}
>> a.keys
=> []
>> a.size
=> 0
>> a[:a].size
=> 1

Другими словами, я не вижу хэш-элемент, когда проверяю хэш, но я могу получить к нему доступ по его ключу.

Является ли это ожидаемым поведением? Что здесь происходит?

Кстати, это Ruby 1.9.1, не пробовал более ранние версии.

Изменить: упрощенный пример, поскольку он не должен быть хешем хэшей хэшей...

4b9b3361

Ответ 1

Ожидается поведение (во всех рубиновых версиях). И если вы немного экспериментируете, вы увидите, что вы всегда получаете доступ к одному и тому же хэшу, независимо от того, какой ключ вы используете:

>> a[:a][:b] = 1
=> 1
>> a[:c][:d] = 2
=> 2
>> a[:d]
=> {:b=>1, :d=>2}

Способ Hash.new с аргументом по умолчанию работает: Если вы выполняете hash[key], он проверяет, существует ли этот ключ в хэше. Если это так, оно возвращает значение для этого ключа. Если он не возвращает значение по умолчанию. Он не добавляет ключ к хешу, и он будет возвращать один и тот же объект по умолчанию (а не копию) каждый раз.

Чтобы получить то, что вы хотите, вы хотите вместо этого указать блок по умолчанию. Таким образом, блок будет выполняться каждый раз, когда вы получаете доступ к ключу, который не находится в хэше. Внутри блока вы можете создать новый хэш и установить ключ для "хэша". Например:

Hash.new { |h,k|  h[k] = {} }