2009-09-14 4 views
0
def test_method 
    ["a", "b", "c"].map {|i| yield(i) } 
end 

Si je l'appelle test_method comme ceci:rendement: pourquoi je ne peux pas écrire: p test_method {} i.upcase

p test_method {|i| i.upcase } 
# => ["A", "B", "C"] 

Pourquoi ai-je besoin {| i |} à l'intérieur du bloc , au lieu de dire simplement ceci:

p test_method { i.upcase } 

La raison pour laquelle je pense est parce que quand le rendement est appelé à test_method, nous avons déjà un {| i |}

["a", "b", "c"].map {|i| yield(i) } 

Répondre

2

Le bloc a besoin d'une valeur paramétrée pour passer à la méthode upcase. Il peut être regardé de cette façon: Si vous omettez le | i | dans le bloc, il n'a aucun moyen de « rattrapage » la valeur a donné (i dans test_method)

0

Au moment où vous appelez

p test_method {|i| i.upcase} 

Le |i| utilisé dans la définition de la méthode n'est pas visible (son champ d'application est uniquement dans le {}. En particulier, vous construisez un bloc qui prend une seule variable, et pour construire ce bloc, vous devez spécifier ce que variable. Notez que

p test_method {|j| j.upcase}

est également valide.

2

Dans Ruby 1.9, vous pouvez écrire:

p test_method &:upcase 
2

Comme l'a dit ennuikiller, vous devez définir ce que vous souhaitez nommer la variable (s) qui est passé en retrait de la déclaration yield. Cela a à voir avec la portée d'une variable. La portée à l'intérieur du bloc que vous transmettez à test_method ne connaît pas la variable i. Vous pouvez réellement appeler cela comme vous le souhaitez.

Par exemple, vous pouvez effectuer les opérations suivantes:

def test_method 
    ["a", "b", "c"].map { |i| yield(i) } 
end 

p test_method { |some_variable_name| some_variable_name.upcase } 

Tout simplement parce que la méthode d'essai le sait, il ne signifie pas que le bloc que vous passez à la méthode d'essai va le savoir.

Edit 1: Pour donner un peu plus d'informations, vous pouvez redéfinir test_method comme suit si elle en fait un peu plus clair:

def test_method(&block) 
    if not block.nil? 
    ["a", "b", "c"].map { |i| yield(i) } 
    end 
end 
3

Si vous venez de fond Groovy où ils ont une itérateur implicite, ou même de Scala où vous pouvez faire sans cela | i | en utilisant des fonctions partielles, vous trouverez peut-être une question logique, cependant, au moment actuel le meilleur que vous pouvez faire en Ruby 1.9 ou même à l'intérieur Rails, est d'utiliser la méthode symbole # de to_block comme JRL mentionné:

p test_method &:upcase 

Il suffit donc d'ajouter le &: avant le nom de la méthode.

Questions connexes