Синтаксис Ruby Proc - PullRequest
       9

Синтаксис Ruby Proc

1 голос
/ 22 декабря 2010

Ответом на вопрос, который я поставил вчера, был следующий фрагмент кода 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? Спаси меня от синтаксиса ада!

Спасибо!

Ответы [ 3 ]

7 голосов
/ 22 декабря 2010

Когда вы префиксите последний аргумент вызова с помощью &, вы ясно даете понять, что отправляете блок, а не normal аргумент. Хорошо, в method(&:something), :something является символом, а не proc , поэтому Ruby автоматически вызывает метод to_proc, чтобы получить реальный блок. И ребята из Rails (а теперь и ванильный Ruby) ловко определили его как:

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]
2 голосов
/ 22 декабря 2010

my_method(&some_value) означает вызвать my_method, передав some_value в слот специального аргумента, proc-слот, обычно зарезервированный для передачи блоков do-notation.

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

Любой объект, который является Proc или который отвечает to_proc, разрешается передавать в proc-slot. Если вы передадите объект, который не является Proc, но который отвечает на to_proc, то Ruby вызовет to_proc для объекта для вас и передаст результат в метод.

Реализация Symbol#to_proc заключается в возврате процедуры, которая при передаче аргумента отправляет этому аргументу сообщение, которое является самим символом. Например, :hello.to_proc.call(my_obj) в конечном итоге сделает my_obj.send :hello.

То есть my_array.each(&:hello) передает :hello в each в слоте proc (где обычно проходит блок, если вы использовали do-нотацию для создания блока). :hello.to_proc.call(my_array[0]) в итоге становится my_array[0].send :hello и одинаковым для всех последующих индексов my_array.

1 голос
/ 22 декабря 2010

равно:

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