Question
Une réponse à une question que je posais hier ici était la pièce de code suivante Ruby:
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 l'enfer de syntaxe!
Merci!
La solution
Lorsque vous préfixe le dernier argument d'un appel avec &
vous indiquant clairement que vous envoyez un bloc et non normale argument. Ok, dans method(&:something)
, :something
est un symbole, pas proc , si Ruby appelle automatiquement la méthode to_proc
pour obtenir un vrai bloc. Et les gars Rails (et maintenant la vanille Ruby) intelligemment définie comme:
class Symbol
def to_proc
proc { |obj, *args| obj.send(self, *args) }
end
end
C'est pourquoi vous pouvez faire:
>> [1, 2, 3].map(&:to_s) # instead of [1, 2, 3].map { |n| n.to_s }
=> ["1", "2", "3"]
[modifier] Remarque: lorsque vous vous rendez compte que cette construction est sans sucre, mais l'infrastructure générique syntactique que Ruby fournit, rien ne vous empêche de mettre en œuvre votre propre to_proc
pour les autres classes. Jamais senti limité parce &: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]
Autres conseils
moyens de my_method(&some_value)
pour invoquer my_method
, en passant dans la fente some_value
argument particulier, la fente de proc, habituellement réservé pour le passage des blocs de notation do.
my_block = lambda { puts "hello" }
(1..3).each(&my_block)
Tout objet qui est un Proc
ou qui répond à to_proc
est autorisé à passer dans la fente de proc. Si vous passez dans un objet qui n'est pas Proc
mais qui répond à to_proc
, puis Ruby appellera to_proc
sur l'objet pour vous et passer le résultat dans la méthode.
La mise en œuvre de Symbol#to_proc
est de renvoyer un proc qui, lorsqu'il est passé un argument, envoie cet argument, le message qui est le symbole lui-même. Par exemple, :hello.to_proc.call(my_obj)
va finir par faire my_obj.send :hello
.
my_array.each(&:hello)
passe :hello
à each
dans la fente de proc (où un bloc normalement passé, si vous avez utilisé la notation faire pour un bloc). se termine :hello.to_proc.call(my_array[0])
jusqu'à être my_array[0].send :hello
, et même pour tous les indices suivants de my_array
.
il est égal à:
ranges.sort_by{|r| r.begin}