2014-09-07 3 views
-1

Voici un exemple avec push:différence entre .Le bouton Ruby et <<

@connections = Hash.new [] 
@connections[1] = @connections[1].push(2) 
puts @connections # => {1=>[2]} 

Voici un exemple avec < <

@connections = Hash.new [] 
@connections[1] << 2 
puts @connections # => {} 

Pour une raison quelconque la sortie (@connections) est différent, mais Pourquoi? Je suppose qu'il a quelque chose à voir avec le modèle d'objet Ruby?

Peut-être que le nouvel objet de hachage [] est créé à chaque fois, mais pas enregistré? Mais pourquoi?

+1

Malheureusement, cela ne répond pas à ma question. Le fait que push accepte plus d'un argument n'explique pas le comportement ci-dessus. – Sergey

+2

Dans votre premier exemple de code, vous n'avez pas simplement remplacé push() par << avez-vous? Vous avez peut-être aussi essayé ce qui suit dans votre deuxième exemple: '@connections [1] .push (2)' et ensuite demandé: "Quelle est la différence entre push() et push()?" – 7stud

Répondre

9

La différence dans votre code n'est pas sur << par rapport à push, c'est sur le fait que vous réaffectez dans un cas et pas dans l'autre. Voici deux morceaux de code sont équivalentes:

@connections = Hash.new [] 
@connections[1] = @connections[1].push(2) 
puts @connections # => {1=>[2]} 

@connections = Hash.new [] 
@connections[1] = (@connections[1] << 2) 
puts @connections # => {1=>[2]} 

Comme sont ces deux:

@connections = Hash.new [] 
@connections[1].push(2) 
puts @connections # => {} 

@connections = Hash.new [] 
@connections[1] << 2 
puts @connections # => {} 

La raison pour laquelle Réaffectation fait une différence ici est que l'accès à une valeur par défaut, ne pas ajouter automatiquement une entrée pour le hash. C'est si vous avez h = Hash.new(0) et puis vous faites p h[0], vous imprimerez 0, mais la valeur de h sera toujours {} (pas {0 => 0}) parce que le 0 n'est pas ajouté au hachage. Si vous faites h[0] += 1, cela appellera la méthode []= sur le hachage et ajoutera effectivement une entrée pour 0, h devient {0 => 1}.

Alors, quand vous faites @connections[1] << 2 dans votre code, vous obtenez le tableau par défaut et effectuer << là-dessus, mais vous ne stockons rien dans @connections, il reste {}. Lorsque vous faites @connections[i] = @connections[i].push(2) ou @connections[i] = (@connections[i] << 2), vous appelez []=, de sorte que l'entrée est ajoutée au hachage.


Cependant, vous devez noter que le hachage renvoie une référence au même tableau à chaque fois, même si vous ajoutez l'entrée du hachage, il sera probablement toujours pas se comporter comme prévu une fois que vous ajoutez plus d'une entrée (puisque toutes les entrées se réfèrent au même tableau):

@connections = Hash.new [] 
@connections[1] = @connections[1].push(2) 
@connections[2] = @connections[2].push(42) 
puts @connections # => {1 => [2, 42], 2 => [2, 42]} 

Qu'est-ce que vous voulez vraiment est un hachage qui renvoie une référence à un nouveau tableau chaque fois qu'une nouvelle clé est accessible et qui ajoute automatiquement une entrée pour le nouveau tableau quand cela arrive. Pour ce faire, vous pouvez utiliser le formulaire de bloc de Hash.new comme ceci:

@connections = Hash.new do |h, k| 
    h[k] = [] 
end 
@connections[1].push(2) 
@connections[2].push(42) 
puts @connections # => {1 => [2], 2 => [42]} 
+0

très bonne réponse. –

+0

Je deuxième @ applaudissement de Marian. –

+0

Vous pouvez également écrire la dernière définition de hachage 'Hash.new {[]}'. –

1

Notez que lorsque vous écrivez

h = Hash.new |this_hash, non_existent_key| { this_hash[non_existent_key] = [] } 

... Ruby exécutera le bloc chaque fois que vous essayez de rechercher une clé qui doesn n'existe pas, puis retourne la valeur de retour du bloc. Un bloc est comme un def en ce que toutes les variables à l'intérieur (y compris les variables de paramètres) sont créées à chaque fois que le bloc est appelé. En outre, notez que [] est un constructeur Array, et chaque fois qu'il est appelé, il crée un nouveau tableau.

Un bloc renvoie le résultat de la dernière déclaration qui a été exécuté dans le bloc, qui est l'instruction d'affectation:

this_hash[non_existent_key] = [] 

Et une instruction d'affectation renvoie le côté droit, qui sera une référence à la Même tableau que celui assigné à la clé dans le hachage, donc toute modification apportée au tableau retourné changera le tableau dans le hachage.

D'autre part, lorsque vous écrivez:

Hash.new([]) 

Le constructeur [] crée un nouveau tableau vide; et que Array devient l'argument de Hash.new(). Il n'y a pas de bloc pour que ruby ​​appelle à chaque fois que vous cherchez une clé non existante, donc ruby ​​retourne juste ce tableau comme valeur pour TOUTES les clés inexistantes - et surtout, rien n'est fait pour le hachage.

Questions connexes