这是ActiveSupport扩展的一个方法。原代码如下:
class Symbol
def to_proc
Proc.new { |*args| args.shift.__send__(self, *args) }
end
end
它扩展出这种用法:
(1..5).map(&:to_s)
map原本是要接受一个block参数,普通的用法是:
(1..5).map{|e| e.to_s}
或者:
proc = Proc.new{|e| e.to_s}
(1..5).map(&proc)
上面这个(1..5).map(&:to_s)用法可以拆成3步来解释:
sym = :to_s
proc = Proc.new{|*args| args.shift.send(sym, *args)}
(1..5).map(&proc)
有个疑问,经过yanping.jia解释,map(&:to_s)因为出现了&符号,所以:to_s会执行to_proc方法,然后与&一起合成&proc交给map处理。虽然说得通,不过我总觉得这个解释中,&这个符号做了2次工作,是否合理?
这种用法原本是Ruby Extensions Project发明的,在RoR中作了点修改。原来的版本是:
class Symbol
def to_proc
proc { |obj, *args| obj.send(self, *args) }
end
end
它使用2个参数来分出一个参数,而RoR版本则使用shift分出来。
刚才又想了一下,yanping.jia的解释应该是合理的,解释器看到&:id时,先会判断是否是一个方法调用,如果是则需要把:id转成一个proc。否则就是语法错误了。