Вопрос

Ответ на вопрос, на котором я задал вчера здесь, был следующим кусочком кода 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}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top