2009-10-01 9 views
8

Aquí es un truco ingenioso para permitir autovivification de hash de rubí (tomado de facetas):rubí de hash autovivification (facetas)

# 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 

pesar de que funciona (por supuesto), me resulta muy frustrante que puede' t averiguar cómo este dos trazador hace lo que hace.

leet se pone como valor predeterminado. Entonces, simplemente accediendo a h['new_key'] de alguna manera lo abre y crea 'new_key' => {}

Ahora, esperaría que h['new_key'] devuelva el valor predeterminado del objeto en lugar de evaluarlo. Es decir, 'new_key' => {} no se crea automáticamente. Entonces, ¿cómo se llama realmente a leet? Especialmente con dos parámetros?

Respuesta

18

El estándar new method for Hash acepta un bloque. Se llama a este bloque en el caso de intentar acceder a una clave en el Hash que no existe. El bloque pasa el Hash mismo y la clave que se solicitó (los dos parámetros) y debe devolver el valor que se debe devolver para la clave solicitada.

Notarás que el leet lambda hace 2 cosas. Devuelve un nuevo Hash con leet como el bloque para manejar los valores predeterminados. Este es el comportamiento que permite que autonew funcione para Hashes de profundidad arbitraria. También asigna este nuevo Hash al hsh[key] para que la próxima vez que solicite la misma clave obtenga el Hash existente en lugar de crear uno nuevo.

+0

Excelente respuesta. – Pesto

+1

De hecho lo es. Esto, en particular, me enseñará a nunca volver a referirme a RubyBook (viene con una distribución estándar de ruby ​​windows), ya que no mencionó ese pequeño hecho irrelevante sobre los bloques y los nuevos. – artemave

8

Es también digno de mención que este código se puede hacer en una sola línea de la siguiente manera:

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

La llamada a la almohadilla # default_proc devuelve el proc que se utilizó para crear la matriz, por lo que tenemos una buena configuración recursiva aquí.

Hablo de un similar case a esto en mi blog.

-1

Alternativamente, podría considerar mi xkeys gem. Es un módulo que puede usar para extender matrices o hashes para facilitar el acceso anidado.

Si buscas algo que aún no existe, obtienes un valor nulo (u otro valor o una excepción si lo prefieres) sin crear nada al mirar. También se puede agregar al final de las matrices.

Puede optar por autovigilar los hashes o matrices para las claves enteras (pero solo una vez para toda la estructura).

Cuestiones relacionadas