Ruby Hash Initializers

Hash Initializers:

# this animals = Hash.new { [] } animals[:dogs] << :Scooby animals[:dogs] << :Scrappy animals[:dogs] << :DynoMutt animals[:squirrels] << :Rocket animals[:squirrels] << :Secret animals #=> {} # is not the same as this animals = Hash.new { |_animals, type| _animals[type] = [] } animals[:dogs] << :Scooby animals[:dogs] << :Scrappy animals[:dogs] << :DynoMutt animals[:squirrels] << :Rocket animals[:squirrels] << :Secret animals #=> {:squirrels=>[:Rocket, :Secret], :dogs=>[:Scooby, :Scrappy, :DynoMutt]} 

I saw someone publish them on a different issue, but I don’t understand why animals appear in the first case. If i print

 animals[:dogs] 

I get the corresponding array.

+4
source share
3 answers

The first form indicates a block that returns a default value for a key that is not found. This means that when animals[:dogs] is called, there is no key :dogs in the hash, so your block is called and animals[:dogs] evaluates the result of your block, i.e. [] . Then what happens is that << :Scooby adds :Scooby to this empty list, which is then successfully discarded.

The second form indicates a block that, when the key is requested and not found, receives the hash itself and the key that was not found as parameters. This is a slightly more powerful version of the first constructor. The difference is what your block is doing. In this second form, you modify the hash to associate [] with a key that was not found. So now it is stored inside the hash and << :Scooby will store :Scooby there. Further calls to :dog will not call the block, because now :dog exists in the hash.

+7
source

In the first case, the default value returned when the key does not exist is [] . Then various statements successfully add different dogs and squirrels to the returned arrays.

However, it is by no means the key ever created for :dogs or :squirrels.

In the second case, the block saves the new value back to the hash record using the key.

Interestingly, here is a little more interesting, as you continue to receive a new empty array in the first case. And the answer is this: you did not pass [] as a parameter, but as a block. This executable file is saved as proc. Each time a key is not found, proc starts again and generates a new [] .

You can see this in the operation, pay attention to the different values ​​of the object identifier:

 irb > t = Hash.new { [] } => {} irb > t[:a].object_id => 2149202180 irb > t[:a].object_id => 2149192500 
+3
source

The reason the first crash and the second is not because of the block that is passed to Hash.new.

This block is used to determine the default type returned when accessing a key that does not yet exist. In the first example, there is no input initializer, so each new key returns {} or an empty Hash . The hash has no << method, so it returns nothing.

The second case works correctly because the write initializer is defined as an empty Array . So, in this case, when you first call animals[:dogs] , it returns [] an empty Array instead of {} an empty Hash . The array has a method called << , so it works successfully and digs a character into the array using the specified key.

Hope this clears up.

0
source

Source: https://habr.com/ru/post/1399287/


All Articles