Initializing hashes

后端 未结 5 1554
傲寒
傲寒 2021-02-07 10:25

I frequently write something like this:

a_hash[\'x\'] ? a_hash[\'x\'] += \' some more text\' : a_hash[\'x\'] = \'first text\'

There ought to be

5条回答
  •  萌比男神i
    2021-02-07 10:59

    There are two ways to create initial values with for a Hash.

    One is to pass a single object in to Hash.new. This works well in many situations, especially if the object is a frozen value, but if the object has internal state, this may have unexpected side-effects. Since the same object is shared between all keys without an assigned value, modifying the internal state for one will show up in all.

    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"
    

    Another initialization method is to pass Hash.new a block, which is invoked each time a value is requested for a key that has no value. This allows you to use a distinct value for each key.

    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"
    

    The block is passed two arguments: the hash being asked for a value, and the key used. This gives you the option of assigning a value for that key, so that the same object will be presented each time a particular key is given.

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

    This last method is the one I most often use. It's also useful for caching the result of an expensive calculation.

提交回复
热议问题