2010-12-22 2 views
1

Une réponse à une question que je posais hier ici était la pièce de code suivante Ruby:Ruby Proc Syntaxe

def overlap?(r1,r2) 
    r1.include?(r2.begin) || r2.include?(r1.begin) 
end 

def any_overlap?(ranges) 
    ranges.sort_by(&:begin).each_cons(2).any? do |r1,r2| 
    overlap?(r1, r2) 
    end 
end 

Je reçois each_cons, mais quelle est la notation &:begin étrange? Sauve-moi de la syntaxe enfer!

Merci!

+0

Ceci plus ou moins un doublon de [Understanding [ClassOne, ClassTwo] .each (&: my_method) '] (http://StackOverflow.Com/q/99318/), [Qu'est-ce que' map (&: name) 'mean dans Ruby?] (http://StackOverflow.Com/q/1217088/), [Qu'est-ce exactement est-ce dans ruby:' &: capitalize'] (http://StackOverflow.Com/q/1792683) /), [Ruby/Ruby on Rails raccourci côlon ampersand] (http://StackOverflow.Com/q/1961030/), [syntaxe Ruby: '&: symbol'] (http://StackOverflow.Com/q/2096975 /), [Qu'est-ce que ce '&: last' Ruby Construct appelé?] (Http://StackOverflow.Com/q/2211751/), ... –

+0

... [Comment appelez-vous l'opérateur' &: ' dans Ruby?] (http://StackOverflow.Com/q/2259775/), [Que fait 'map (&: name)' dans ce code Ruby?] (http://StackOverflow.Com/q/2388337/), [Que sont ': +' et '& +' dans ruby?] (http://StackOverflow.Com/q/2697024/) et ['&: views_count' dans' Post.published.collect (&: views_count) '] (http://StackOverflow.Com/q/3888044/) . –

Répondre

7

Lorsque vous préfixer le dernier argument d'un appel avec & vous en indiquant clairement que vous envoyez un bloc et non un argument de normal. Ok, dans method(&:something), :something est un symbole, pas un proc, alors Ruby appelle automatiquement la méthode to_proc pour obtenir un vrai bloc. Et Rails gars (et maintenant vanillé aussi Ruby) intelligemment définis comme:

class Symbol 
    def to_proc 
    proc { |obj, *args| obj.send(self, *args) } 
    end 
end 

C'est la raison pour laquelle vous pouvez faire:

>> [1, 2, 3].map(&:to_s) # instead of [1, 2, 3].map { |n| n.to_s } 
=> ["1", "2", "3"] 

[modifier] Note: lorsque vous vous rendez compte que cette construction est sans sucre syntactique mais l'infrastructure générique que fournit Ruby, rien ne vous empêche d'implémenter votre propre to_proc pour d'autres classes. Jamais senti limité parce que &:method permis pas d'arguments?

class Array 
    def to_proc 
    proc { |obj, *args| obj.send(*(self + args)) } 
    end 
end 

>> ["1", "F", "FF"].map(&[:to_i, 16]) 
=> [1, 15, 255] 
1

il est égal à:

ranges.sort_by{|r| r.begin} 
+0

Très bien, mais ce n'est pas vraiment une explication! – mbm

+0

désolé, @mbm. La raison est & va invoquer la méthode to_proc. –

1

my_method(&some_value) moyens pour appeler my_method, en passant dans la fente some_value argument particulier, la fente de proc, habituellement réservé pour le passage des blocs do-notation.

my_block = lambda { puts "hello" } 
(1..3).each(&my_block) 

Tout objet qui est une Proc ou qui répond à to_proc est autorisé à passer dans la fente de proc. Si vous passez un objet qui n'est pas un Proc mais qui répond à to_proc, alors Ruby appellera pour vous le to_proc et passera le résultat dans la méthode.

L'implémentation de Symbol#to_proc consiste à renvoyer un proc qui, passé un argument, envoie à cet argument le message correspondant au symbole lui-même. Par exemple, :hello.to_proc.call(my_obj) finira par faire my_obj.send :hello.

Donc my_array.each(&:hello) passe :hello à each dans le proc-slot (où un bloc serait normalement passé, si vous avez utilisé la notation Do pour faire un bloc). :hello.to_proc.call(my_array[0]) finit par être my_array[0].send :hello, et le même pour tous les index suivants de my_array.