2010-11-21 17 views
30

Quelqu'un peut-il m'expliquer l'utilisation par Ruby de personnages de pipe dans un bloc? Je comprends qu'il contient un nom de variable auquel seront affectées les données lors de leur itération. Mais comment s'appelle-t-il? Peut-il y avoir plus d'une variable à l'intérieur des tuyaux? Autre chose que je devrais savoir à ce sujet? De bons liens vers plus d'informations à ce sujet?Quelqu'un peut-il expliquer l'utilisation de Ruby dans un bloc?

Par exemple:

25.times { | i | puts i } 
+0

Question connexe: http://stackoverflow.com/questions/665576/what-are-those-pipe-symbols-for-in-ruby –

Répondre

27

accolades définissent une fonction anonyme, appelée un bloc. Les jetons entre les tuyaux sont les arguments de ce bloc. Le nombre d'arguments requis dépend de la façon dont le bloc est utilisé. Chaque fois que le bloc est évalué, la méthode nécessitant le bloc transmettra une valeur basée sur l'objet qui l'appelle.

Cela revient à définir une méthode, mais elle n'est pas stockée au-delà de la méthode qui accepte un bloc.

Par exemple:

def my_print(i) 
    puts i 
end 

fera la même chose que quand exécuté:

{|i| puts i} 

la seule différence est le bloc est défini à la volée et ne sont pas stockées.

Exemple 2: Les déclarations suivantes sont équivalentes

25.times &method(:my_print) 

25.times {|i| puts i} 

Nous utilisons des blocs anonymes parce que la majorité des fonctions passées en un bloc sont généralement spécifiques à votre situation et ne vaut pas la définition de la réutilisation.

Alors, que se passe-t-il lorsqu'une méthode accepte un bloc? Cela dépend de la méthode.Les méthodes qui acceptent un bloc l'appellent en passant des valeurs de leur objet appelant d'une manière bien définie. Ce qui est retourné dépend de la méthode nécessitant le bloc. Par exemple: En 25.times {|i| puts i} .times appelle le bloc une fois pour chaque valeur comprise entre 0 et la valeur de son appelant, en passant la valeur dans le bloc comme variable temporaire i. Times renvoie la valeur de l'objet appelant. Dans ce cas 25.

Regardons la méthode qui accepte un bloc avec deux arguments.

{:key1 => "value1", :key2 => "value2"}.each {|key,value| 
    puts "This key is: #{key}. Its value is #{value}" 
} 

Dans ce cas, chacun appelle les séquences de chaque paire clé/valeur passage de la clé comme premier argument et la valeur que le second argument.

+1

& my_print est une syntaxe invalide, vous voulez dire & méthode (: my_print) – horseyguy

+0

Vous êtes rampe droite. Je n'ai pas eu le temps de tester cet exemple, je le savais et est utilisé pour traiter la valeur d'une variable en tant que Proc. J'ai juste oublié que les méthodes ne contiennent pas de valeurs. J'ai mis à jour l'exemple. Merci d'avoir fait remarquer cela. – EmFi

+4

Merci pour une bonne explication d'un concept si étrange pour ceux d'entre nous qui viennent de Java. – Andy

5

Les tuyaux spécifient les arguments qui sont remplis avec des valeurs par la fonction qui appelle votre bloc. Il peut y avoir zéro ou plusieurs d'entre eux, et combien vous devriez utiliser dépend de la méthode que vous appelez. Par exemple, each_with_index utilise deux variables et place l'élément dans l'une d'entre elles et l'index dans l'autre.

here is a good description of how blocks and iterators work

2

arguments de blocs suivent toutes les mêmes conventions que les paramètres de la méthode (au moins 1,9): vous pouvez définir des arguments optionnels, longueur variable des listes de arg, par défaut, etc. Voici un pretty decent summary. Quelques points à prendre en compte: comme les blocs voient les variables dans la portée, ils ont été définis, si vous transmettez un argument avec le même nom qu'une variable existante, il va "l'ombre" - votre bloc verra le passé en valeur et la variable d'origine sera inchangée.

i = 10 
25.times { | i | puts i } 
puts i #=> prints '10' 

Imprime '10' à la fin. Parce que parfois c'est un comportement souhaitable même si vous ne transmettez pas de valeur (vous voulez vous assurer que vous ne coupez pas accidentellement une variable de la portée environnante), vous pouvez spécifier des noms de variables locales après un point-virgule après la liste d'arguments:

x = 'foo' 
25.times { | i ; x | puts i; x = 'bar' } 
puts x #=> prints 'foo' 

ici, « x » est locale au bloc, même si aucune valeur n'est passée.