2012-02-29 23 views
8

Rubí le permite definir valores por defecto para los hashes:Modificar el valor hash predeterminado

h=Hash.new(['alright']) 
h['meh'] # => ["alright"] 

asignación de un valor aparece cuando se muestra el hash, sino un defecto modificada no. ¿Dónde está 'bad'?

h['good']=['fine','dandy'] 
h['bad'].push('unhappy') 
h # => {"good"=>["fine", "dandy"]} 

'bad' muestra arriba si nos preguntamos de forma explícita.

h['bad'] # => ["alright", "unhappy"] 

¿Por qué el valor predeterminado modificado no aparece cuando se muestra el hash?

+0

Pregunta legítima, pero es probable que sea un duplicado. –

Respuesta

11

de Hash no lo hace trabaja como lo esperas. Cuando usted dice h[k], el proceso es así:

  1. Si tenemos una clave k, devolver su valor.
  2. Si tenemos un valor predeterminado para el Hash, devuelva ese valor predeterminado.
  3. Si tenemos un bloque para proporcionar valores predeterminados, ejecute el bloque y devuelva su valor de retorno.

Tenga en cuenta que (2) y (3) no dicen nada sobre la inserción de k en el hash. El valor por defecto se convierte esencialmente en h[k] esto:

h.has_key?(k) ? h[k] : the_default_value 

Así que simplemente accediendo a una clave inexistente, y obtener el valor por defecto de atrás no se agregará la clave que falta a la Hash.

Por otra parte, nada de la forma:

Hash.new([ ... ]) 
# or 
Hash.new({ ... }) 

es casi siempre un error, ya que va a compartir exactamente la misma matriz por defecto o por Hash para todos los valores por defecto. Por ejemplo, si usted hace esto:

h = Hash.new(['a']) 
h[:k].push('b') 

Entonces h[:i], h[:j], ... todos volveremos ['a', 'b'] y que rara vez es lo que quiere.

Creo que estás en busca de la block form of the default value:

h = Hash.new { |h, k| h[k] = [ 'alright' ] } 

que va a hacer dos cosas:

  1. Acceso a una clave inexistente va a añadir que la clave para el hash y que tendrá la matriz proporcionada como su valor.
  2. Todos los valores predeterminados serán objetos distintos, por lo que alterar uno no alterará el resto.
2

Lo que pasa es que tiene modificado el valor por defecto del hash, por push ing 'infeliz' en h['bad']. Lo que no ha hecho en realidad se ha agregado como "malo" al hash, por lo que no aparece cuando inspecciona h.

Después de todo el código que ha proporcionado, he intentado esto:

>> p h['bleh'] 
=> ["allright", "unhappy"] 

que sin duda me hace pensar que el valor por defecto se ha cambiado. En respuesta a la pregunta '¿Por qué el defecto modificado no aparecen cuando se muestra el hash?', Se tendría que añadir un elemento a ella, en lugar de acceder a él: valor predeterminado

>> h['bleh'] # Doesn't add 'bleh' to the hash 
>> p h 
=> {"good"=>["fine", "dandy"]} # See, no extra values 

>> h['bleh'] = h.default # Does add a new key with the default value 
>> p h 
=> {"good"=>["fine", "dandy"], "bleh"=>["allright", "unhappy"]} 
+1

Wow. Estoy totalmente corregido. Pero ahora estoy perplejo sobre POR QUÉ ese es el caso. [] es un método en un objeto hash, que devuelve un resultado. ¿Por qué enviar push a ese cambio el hash predeterminado? Es hora de comenzar a cavar a través del código fuente de rubí ... –

+0

Lo tengo. El objeto Hash todavía contiene referencia a la matriz que se está actualizando. Borrando mi respuesta. :) –

+1

Supongo que el valor predeterminado es una referencia a la matriz pasada al constructor de Hash. Cuando 'presionas' sobre eso, estás modificando directamente la matriz en lugar de crear una copia. Para un ejemplo más simple: 'h = Hash.new ('hello'); h ['algo'] << 'aaa'; pone h.default' devolverá 'helloaaa' –

Cuestiones relacionadas