Ruby Proc语法
我昨天提出的一个问题的答案是下面这段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
是一个符号,而不是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"]
注意:当你意识到这个构造不是syntically sugar,而是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]
它等于:
ranges.sort_by{|r| r.begin}
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
的实现是返回一个proc,当传递一个参数的时候,这个proc就会发送这个参数,这个消息就是这个符号本身。 例如, :hello.to_proc.call(my_obj)
最终会做my_obj.send :hello
。
因此, my_array.each(&:hello)
会传入:hello
给each
proc-slot(如果你使用do-notation来创build一个块,通常会通过一个块)。 :hello.to_proc.call(my_array[0])
最终是my_array[0].send :hello
,对于my_array
所有后续索引都是一样的。