49 votes

Comment fonctionne l'opérateur de pelle (<<) dans Ruby Hash?

J'ai été en passant par Ruby Koans tutoriel de la série, quand je suis tombé sur ça 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

Les valeurs en assert_equals, est effectivement ce que le tutoriel prévu. Mais je ne pouvais pas comprendre comment il y a une différence entre l'utilisation d' << de l'opérateur et de l' = opérateur?

Mon espoir était que:

  • hash[:one] serait ["uno"]
  • hash[:two] serait ["dos"]
  • hash[:three] serait []

Quelqu'un peut-il expliquer pourquoi mon attente était mal?

66voto

Gazler Points 23588

Vous avez mélangé la façon dont cela fonctionne un peu. Tout d'abord, une table de Hachage n'ont pas d' << méthode, cette méthode dans votre exemple, il existe sur le tableau.

La raison que votre code n'est pas erroring est parce que vous êtes de passage à une valeur par défaut à votre hash par le constructeur. http://ruby-doc.org/core-1.9.3/Hash.html#method-c-new

hash = Hash.new([])

Cela signifie que si une clé n'existe pas, alors il va retourner un tableau. Si vous exécutez le code suivant:

hash = {}
hash[:one] << "uno"

Ensuite, vous recevrez un non défini erreur de méthode.

Donc dans votre exemple, ce qui se passe réellement est:

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 raison pour laquelle il ne veut pas retourner un tableau avec un élément à chaque fois que vous pouvez vous attendre, c'est parce qu'il stocke une référence à la valeur que vous passer par le constructeur. Ce qui signifie que chaque fois qu'un élément est poussé, il modifie la table initiale.

59voto

Dominik Honnef Points 8050

Quand vous faites l' hash = Hash.new([]) vous créez une table de Hachage dont la valeur par défaut est exactement le même Tableau instance pour toutes les touches. Donc, chaque fois que vous accédez à une clé qui n'existe pas, vous recevez en retour le même Tableau.

h = Hash.new([])
h[:foo].object_id # => 12215540
h[:bar].object_id # => 12215540

Si vous voulez un tableau par clé, vous devez utiliser le bloc de la syntaxe de l' Hash.new:

h = Hash.new { |h, k| h[k] = [] }
h[:foo].object_id # => 7791280
h[:bar].object_id # => 7790760

Edit: voir Aussi ce que Gazler est-à-dire à l'égard de l' #<< méthode et sur ce que l'objet que vous êtes en fait en l'appelant.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X