Ruby Hash Initializer - PullRequest
       20

Ruby Hash Initializer

4 голосов
/ 02 марта 2012

Инициализаторы хеша:

# 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]}

Я видел, как кто-то опубликовал их по другому вопросу, но я не понимаю, почему животные в первом случае кажутся пустыми Если я наберу

animals[:dogs]

Я получаю соответствующий массив.

Ответы [ 3 ]

7 голосов
/ 02 марта 2012

Первая форма указывает блок, который возвращает значение по умолчанию для ключа, который не найден. Это означает, что когда вы вызываете animals[:dogs], в хэше нет ключа :dogs, поэтому ваш блок вызывается и animals[:dogs] оценивает результат вашего блока, то есть []. В таком случае << :Scooby добавляет :Scooby к этому пустому списку, который затем удачно удаляется.

Вторая форма определяет блок, который, когда ключ запрашивается и не найден, получает в качестве параметров сам хэш и ключ, который не был найден. Это немного более мощная версия первого конструктора. Разница в том, что делает ваш блок. Во второй форме вы изменяете хеш, чтобы связать [] с ключом, который не был найден. Так что теперь он хранится внутри хеша и << :Scooby будет хранить там :Scooby. Дальнейшие вызовы :dog не вызовут блокировку, потому что теперь в хэше существует :dog.

3 голосов
/ 02 марта 2012

В первом случае значением по умолчанию, возвращаемым, когда ключ не существует, является [].Затем различные операторы успешно добавляют различных собак и белок в возвращаемые массивы.

Однако ни в коем случае не существует ключа, когда-либо созданного для :dogs или :squirrels.

Во втором случаеблок действительно сохраняет новое значение в хеш-записи, используя ключ.

Одна вещь, которая несколько интересна, это то, как вы продолжаете получать новый пустой массив обратно в первом случае.И ответ таков: вы не передали [] как параметр, а как блок.Это исполняемый файл, и он сохраняется как процесс.Каждый раз, когда ключ не найден, процесс запускается снова и генерирует новый [].

Вы можете увидеть это в действии, обратите внимание на различные значения идентификатора объекта:

irb > t = Hash.new { [] }
 => {} 
irb > t[:a].object_id
 => 2149202180 
irb > t[:a].object_id
 => 2149192500 
0 голосов
/ 02 марта 2012

Причина первого сбоя, а второго нет - из-за блока, который передается в Hash.new.

Этот блок служит для определения типа по умолчанию, возвращаемого при доступе к ключу, который непока существует.В первом примере инициализатор записей отсутствует, поэтому каждый новый ключ возвращает {} или пустой Hash.У хэша нет метода <<, поэтому он ничего не возвращает.

Второй случай работает правильно, поскольку инициализатор записи определен как пустой Array.Таким образом, в этом случае при первом обращении к animals[:dogs] возвращается [] пустой Array вместо {} пустой Hash.Массив действительно имеет метод с именем <<, поэтому он успешно работает и помещает символ в массив по указанному ключу.

Надеюсь, это очистит его.

...