2017-04-18 1 views
-2

Pourquoi ce bloc de code produit-il [1, 2, 3, 4, 5] et non [2, 3, 4, 5, 6]?Comportement de chaque itérateur en ruby ​​

x = [1, 2, 3, 4, 5] 
x.each do |a| 
    a + 1 
end 

Je vu la source de each à https://ruby-doc.org/core-2.2.0/Array.html#method-i-each. Quelque chose comme ceci est écrit là.

   VALUE 
rb_ary_each(VALUE array) 
{ 
    long i; 
    volatile VALUE ary = array; 

    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); 
    for (i=0; i<RARRAY_LEN(ary); i++) { 
     rb_yield(RARRAY_AREF(ary, i)); 
    } 
    return ary; 
} 

Quelqu'un peut-il expliquer?

Répondre

1

De ce qui suit, 'ary' est logiquement égal à array. Notez que la ligne est absente des nouvelles versions de Ruby telles que 2.4.0!

volatile VALUE ary = array; 

Je saute RETURN_SIZED_ENUMERATOR car un bloc est donné. Reportez-vous à sa source à include/ruby ​​/ intern.h.

Ensuite, nous allons dans un 'for' pour chaque élément du tableau 'ary'.

Ensuite, c'est la ligne qui vous intrigue, je crois. Tout d'abord, il prend le i-ème élément du tableau 'ary' via la macro RARRAY_AREF. Deuxièmement, il a passé la valeur de l'élément au bloc donné (c'est-à-dire 'a + 1') via rb_yield. Ainsi, il ne stocke rien.

rb_yield(RARRAY_AREF(ary, i)); 

Depuis rien n'a été écrit à rb_yield, la fonction retourne le tableau « aire » qui est [voir ci-dessus] est entrée « array ».

En le comparant à 'map!' peut vous aider davantage:

static VALUE rb_ary_collect_bang(VALUE ary) 
{ 
    long i; 

    RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length); 
    rb_ary_modify(ary); 
    for (i = 0; i < RARRAY_LEN(ary); i++) { 
     rb_ary_store(ary, i, rb_yield(RARRAY_AREF(ary, i))); 
    } 
    return ary; 
} 

Remarque Appel de fonction 'rb_ary_store' dans la boucle 'for'. C'est la chose! C'est rb_yield-s comme dans chaque variante, mais cela ne gomme pas le résultat retourné. Le résultat est stocké dans le i-ième élément de notre tableau [aimé] 'ary'.

+0

Personnellement, je trouve [cette implémentation] (https://github.com/rubinius/rubinius/blob/master/core/array.rb#L64-L77) beaucoup plus facile à lire que YARV. –

3

Il génère l'objet, vous appelez each, car il s'agit de la valeur de retour de each.

Si vous voulez simplement imprimer le a + 1, vous devriez vraiment faire être sortie:

x.each do |a| 
    puts a + 1 
end 

Ou, si le résultat souhaité est [2, 3, 4, 5, 6] - vous voulez Enumerable#map, pas each. Permettez-moi de passer en revue les lignes principales.

x.map { |a| a + 1 } 
#=> [2, 3, 4, 5, 6] 
+0

J'ai essayé avec met a + 1 ... mais cela imprime à la fois [2, 3, 4, 5, 6] et [1, 2, 3, 4, 5] –

+0

@AmitAuddy s'il vous plaît, lire ma réponse * jusqu'à la fin*. –

+0

@AmitAuddy le code Ruby que vous avez posté en question n'imprime rien. C'est l'interpréteur interactif ('irb') qui imprime la valeur de chaque expression évaluée. Lorsque le code est exécuté en utilisant 'ruby', il ne produit aucune sortie. – axiac