2009-10-01 16 views
8

ecco un trucco intelligente per consentire hash autovivificazione in Ruby (tratto da sfaccettature):rubino hash autovivificazione (sfaccettature)

# 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 

Anche se funziona (ovviamente), lo trovo davvero frustrante che posso' t capire come questa due fodera fa quello che fa.

il leet viene inserito come valore predefinito. Quindi, accedendo semplicemente a h['new_key'] in qualche modo, viene visualizzato e creato 'new_key' => {}

Ora, mi aspetto che l'oggetto valore di default sia h['new_key'] anziché valutarlo. Cioè, 'new_key' => {} non viene creato automaticamente. Quindi come viene effettivamente chiamato leet? Soprattutto con due parametri?

risposta

18

Lo standard new method for Hash accetta un blocco. Questo blocco viene chiamato in caso di tentativo di accedere a una chiave nell'Hash che non esiste. Il blocco passa l'Hash stesso e la chiave richiesta (i due parametri) e deve restituire il valore che deve essere restituito per la chiave richiesta.

Si noterà che il lambda leet fa 2 cose. Restituisce un nuovo hash con leet come blocco per la gestione dei valori predefiniti. Questo è il comportamento che consente a autonew di funzionare per gli hash di profondità arbitraria. Assegna anche questo nuovo hash a hsh[key] in modo che la prossima volta che richiedi la stessa chiave otterrai l'hash esistente anziché uno nuovo creato.

+0

Ottima risposta. – Pesto

+1

In effetti lo è. Questo, in particolare, mi insegnerà a non riferirmi mai più a RubyBook (fornito con una distribuzione standard di ruby ​​windows), dal momento che non ha menzionato quel piccolo fatto irrilevante su blocchi e nuovi. – artemave

8

E 'anche interessante notare che questo codice può essere trasformato in un one-liner come segue:

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

La chiamata al cancelletto # default_proc restituisce il proc che è stato utilizzato per creare il genitore, quindi abbiamo un bella configurazione ricorsiva qui.

Parlo di uno similar case su questo sul mio blog.

-1

In alternativa, è possibile considerare il mio xkeys gem. È un modulo che puoi usare per estendere matrici o hash per facilitare l'accesso annidato.

Se si cerca qualcosa che non esiste ancora, si ottiene un valore nullo (o un altro valore o un'eccezione se si preferisce) senza creare nulla guardando. Può anche aggiungere alla fine degli array.

È possibile scegliere di autovivificare gli hash o gli array per le chiavi integer (ma solo una volta per l'intera struttura).