2009-10-01 4 views
8

Вот умный трюк для того, чтобы хэш autovivification в рубин (из граней):рубин хэш autovivification (фасеты)

# File lib/core/facets/hash/autonew.rb, line 19 
    def self.autonew(*args) 
    leet = lambda { |hsh, key| hsh[key] = new(&leet) } 
    new(*args,&leet) 
    end 

Хотя это работает (конечно), я считаю, это очень расстраивает, что я могу» t выяснить, как это делают два лайнера, что он делает.

leet ставится как значение по умолчанию. Так что тогда просто доступ к h['new_key'] каким-то образом вызывает его и создает 'new_key' => {}

Теперь, я ожидаю, что h['new_key'] вернет объект значения по умолчанию, а не его оценку. То есть, 'new_key' => {} не создается автоматически. Итак, как на самом деле получать звонки? Особенно с двумя параметрами?

ответ

18

Стандарт new method for Hash принимает блок. Этот блок вызывается в случае попытки доступа к ключу в Хэше, который не существует. Блок передается сам Хэш и запрошенный ключ (два параметра) и должен возвращать значение, которое должно быть возвращено для запрошенного ключа.

Вы заметите, что лямбда leet делает 2 вещи. Он возвращает новый Hash с leet как блок для обработки значений по умолчанию. Это поведение, которое позволяет autonew работать на хэши произвольной глубины. Он также присваивает этому новому Hash hsh[key], так что в следующий раз, когда вы запросите тот же ключ, вы получите существующий Hash, а не новый.

+0

Отличный ответ. – Pesto

+1

Действительно. Это, в частности, научит меня больше никогда не ссылаться на RubyBook (поставляется со стандартным дистрибутивом рубинов), поскольку он не упоминал о том, что крошечный нерелевантный факт о блоках и новых. – artemave

8

Стоит также отметить, что этот код может быть сделана в однострочник следующим образом:

def self.autonew(*args) 
    new(*args){|hsh, key| hsh[key] = Hash.new(&hsh.default_proc) } 
end 

Вызов Hash # default_proc возвращает процедурный, который был использован для создания родителя, так что мы имеем Хорошая рекурсивная установка здесь.

В этом блоге я расскажу об similar case.

-1

В качестве альтернативы, вы можете рассмотреть мой xkeys gem. Это модуль, который можно использовать для расширения массивов или хешей для облегчения вложенного доступа.

Если вы ищете что-то, что еще не существует, вы получите нулевое значение (или другое значение или исключение, если хотите), не создавая ничего, глядя. Он также может присоединяться к концу массивов.

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

Смежные вопросы