Существует два способа создания начальных значений для Hash
.
Один - передать один объект в Hash.new
. Это хорошо работает во многих ситуациях, особенно если объект является замороженным значением, но если объект имеет внутреннее состояние, это может иметь неожиданные побочные эффекты. Поскольку один и тот же объект используется совместно для всех клавиш без назначенного значения, изменение внутреннего состояния для одного будет отображаться во всех.
a_hash = Hash.new "initial value"
a_hash['a'] #=> "initial value"
# op= methods don't modify internal state (usually), since they assign a new
# value for the key.
a_hash['b'] += ' owned by b' #=> "initial value owned by b"
# other methods, like #<< and #gsub modify the state of the string
a_hash['c'].gsub!(/initial/, "c's")
a_hash['d'] << " modified by d"
a_hash['e'] #=> "c's value modified by d"
Другой метод инициализации - передать Hash.new
блок, который вызывается каждый раз, когда запрашивается значение для ключа, который не имеет значения. Это позволяет вам использовать отдельное значение для каждого ключа.
another_hash = Hash.new { "new initial value" }
another_hash['a'] #=> "new initial value"
# op= methods still work as expected
another_hash['b'] += ' owned by b'
# however, if you don't assign the modified value, it's lost,
# since the hash rechecks the block every time an unassigned key's value is asked for
another_hash['c'] << " owned by c" #=> "new initial value owned by c"
another_hash['c'] #=> "new initial value"
Блоку передаются два аргумента: запрашивается хеш для значения и используемый ключ. Это дает вам возможность назначить значение для этого ключа, так что один и тот же объект будет представлен каждый раз, когда дается конкретный ключ.
yet_another_hash = Hash.new { |hash, key| hash[key] = "#{key}'s initial value" }
yet_another_hash['a'] #=> "a's initial value"
yet_another_hash['b'] #=> "b's initial value"
yet_another_hash['c'].gsub!('initial', 'awesome')
yet_another_hash['c'] #=> "c's awesome value"
yet_another_hash #=> { "a" => "a's initial value", "b" => "b's initial value", "c" => "c's awesome value" }
Этот последний метод я использую чаще всего. Это также полезно для кэширования результатов дорогостоящих вычислений.