2009-10-01 16 views
8

Oto sprytny podstęp, aby umożliwić hash autovivification w Ruby (zaczerpnięte z aspektów):rubin hash autovivification (fasety)

# 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 

Chociaż to działa (oczywiście), uważam, że to naprawdę frustrujące, że mogę” t wymyślić, jak ta dwulistnica robi to, co robi.

Leet jest umieszczany jako wartość domyślna. Tak więc wtedy uzyskanie dostępu do h['new_key'] w jakiś sposób podnosi go i tworzy 'new_key' => {} Teraz oczekiwałbym, że powróci domyślny obiekt wartości, w przeciwieństwie do jego oceny. Oznacza to, że 'new_key' => {} nie jest automatycznie tworzony. W jaki więc sposób leet zostaje wywołany? Zwłaszcza z dwoma parametrami?

Odpowiedz

18

Standard new method for Hash przyjmuje blok. Blok ten wywoływany jest w przypadku próby uzyskania dostępu do klucza w mieszaniu, który nie istnieje. Blok jest przekazywany do samego skrótu i ​​żądanego klucza (dwóch parametrów) i powinien zwracać wartość, która powinna zostać zwrócona dla żądanego klucza.

Zauważysz, że lambda leet ma 2 rzeczy. Zwraca nową wartość skrótu o numerze leet jako blok obsługi wartości domyślnych. Jest to zachowanie, które pozwala autonew pracować dla Hashów o dowolnej głębokości. Przypisuje również tę nową mieszankę do hsh[key], aby następnym razem zażądać tego samego klucza, a otrzymasz istniejący skrót, a nie nowy.

+0

Doskonała odpowiedź. – Pesto

+1

Rzeczywiście tak jest. To, w szczególności, nauczy mnie, żebym nigdy więcej nie odwoływał się do RubyBook (pochodzi ze standardową dystrybucją okien ruby), ponieważ nie wspomniał o tym małym nieistotnym fakcie dotyczącym bloków i nowego. – artemave

8

Warto również zauważyć, że ten kod może być wykonane w jednym-liner następująco:

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

Wezwanie do krzyżyka # default_proc zwraca proc, który został użyty do utworzenia rodzica, więc mamy fajna konfiguracja rekursywna tutaj.

Mówię o tym na moim blogu na temat similar case.

-1

Ewentualnie możesz rozważyć moją xkeys gem. Jest to moduł, którego można użyć do rozszerzenia tablic lub skrótów w celu ułatwienia dostępu zagnieżdżonego.

Jeśli szukasz czegoś, co jeszcze nie istnieje, otrzymasz wartość zerową (lub inną wartość lub wyjątek, jeśli wolisz) bez tworzenia czegokolwiek przez wygląd. Może również dołączyć się do końca tablic.

Można wybrać opcję autowagania skrótów lub tablic dla klawiszy całkowitych (ale tylko jeden raz dla całej struktury).