Вопрос
Ответ на вопрос, на котором я задал вчера здесь, был следующим кусочком кода 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
я получил each_cons
, но что странно &:begin
обозначение? Спасите меня от синтаксиса ада!
Спасибо!
Решение
Когда вы префикс последний аргумент вызова с &
Вы даете понять, что отправляете блок, а не обычный аргумент ОК, в method(&:something)
, :something
это символ, а не прокурор, поэтому Ruby автоматически вызывает метод to_proc
Чтобы получить настоящий блок. И ребята Rails (а теперь также ванильный рубин) умело определили это как:
class Symbol
def to_proc
proc { |obj, *args| obj.send(self, *args) }
end
end
Вот почему вы можете сделать:
>> [1, 2, 3].map(&:to_s) # instead of [1, 2, 3].map { |n| n.to_s }
=> ["1", "2", "3"]
РЕДАКТИРОВАТЬ] ПРИМЕЧАНИЕ. Когда вы понимаете, что эта конструкция не является синтатическим сахаром, а общая инфраструктура, которую предоставляет Ruby, ничто не мешает вам реализовать свой собственный to_proc
для других классов. Никогда не чувствовал себя ограниченным, потому что &:method
не допускает никаких аргументов?
class Array
def to_proc
proc { |obj, *args| obj.send(*(self + args)) }
end
end
>> ["1", "F", "FF"].map(&[:to_i, 16])
=> [1, 15, 255]
Другие советы
my_method(&some_value)
означает вызвать my_method
, прохождение some_value
В специальном слоте аргументов Proc-Slot, обычно зарезервированный для прохождения блоков Do-Notation.
my_block = lambda { puts "hello" }
(1..3).each(&my_block)
Любой объект, который является Proc
или что реагирует на to_proc
разрешено передаваться в Proc-Slot. Если вы передаете объект, который не является Proc
но что реагирует на to_proc
, тогда Руби позвонит to_proc
на объекте для вас и передайте результат в метод.
Реализация Symbol#to_proc
это вернуть PROC, который при принятии аргумента посылает этот аргумент о самом символе. Например, :hello.to_proc.call(my_obj)
в конечном итоге сделает my_obj.send :hello
.
Так my_array.each(&:hello)
проходы :hello
к each
В Proc-Slot (где блок обычно проходил, если вы использовали девственную ноцию, чтобы сделать блок). :hello.to_proc.call(my_array[0])
заканчивается тем, что my_array[0].send :hello
, и то же самое для всех последующих индексов my_array
.
это равно:
ranges.sort_by{|r| r.begin}