rails - ruby hash to json
¿Cómo funciona el operador de pala(<<) en Ruby Hashes? (2)
Estaba repasando la serie de tutoriales de Ruby Koans , cuando me about_hashes.rb
esto en about_hashes.rb
:
def test_default_value_is_the_same_object
hash = Hash.new([])
hash[:one] << "uno"
hash[:two] << "dos"
assert_equal ["uno", "dos"], hash[:one]
assert_equal ["uno", "dos"], hash[:two]
assert_equal ["uno", "dos"], hash[:three]
assert_equal true, hash[:one].object_id == hash[:two].object_id
end
Los valores en assert_equals
, es en realidad lo que el tutorial esperaba. Pero no pude entender cómo hay una diferencia entre usar <<
operador y =
operador?
Mi expectativa era que:
-
hash[:one]
sería["uno"]
-
hash[:two]
sería["dos"]
-
hash[:three]
sería[]
¿Puede alguien explicar por qué mi expectativa era incorrecta?
Cuando está haciendo hash = Hash.new([])
, está creando un hash cuyo valor predeterminado es la misma instancia Array para todas las claves. Entonces, cuando accedas a una clave que no existe, obtienes la misma Matriz.
h = Hash.new([])
h[:foo].object_id # => 12215540
h[:bar].object_id # => 12215540
Si desea una matriz por clave, debe usar la sintaxis de bloque de Hash.new
:
h = Hash.new { |h, k| h[k] = [] }
h[:foo].object_id # => 7791280
h[:bar].object_id # => 7790760
Editar: También vea lo que Gazler tiene que decir con respecto al método #<<
y sobre qué objeto realmente lo está llamando.
Has mezclado la forma en que esto funciona un poco. En primer lugar, un Hash no tiene un método <<
, ese método en su ejemplo existe en el conjunto.
La razón por la cual su código no está cometiendo errores es porque está pasando un valor predeterminado a su hash a través del constructor. http://ruby-doc.org/core-1.9.3/Hash.html#method-c-new
hash = Hash.new([])
Esto significa que si una clave no existe, devolverá una matriz. Si ejecuta el siguiente código:
hash = {}
hash[:one] << "uno"
Entonces obtendrá un error de método indefinido.
Entonces en tu ejemplo, lo que realmente está sucediendo es:
hash = Hash.new([])
hash[:one] << "uno" #hash[:one] does not exist so return an array and push "uno"
hash[:two] << "dos" #hash[:two] does not exist, so return the array ["uno"] and push "dos"
La razón por la que no devuelve una matriz con un elemento cada vez, como se puede esperar, es porque almacena una referencia al valor que se transfiere al constructor. Lo que significa que cada vez que se empuja un elemento, modifica la matriz inicial.