很久以前读Rails的源码发现了这个很有意思的东西.
&:foo
一直以为这玩意只是{|item| item.foo}的语法糖而已.
然而今天去查证了一下发现还有一些需要补充的细节
我一直以为是&:/foo 然而正确的理解应该是&/:foo (/代表在这停顿w)
:foo应该是一个完整的Symbol.而&的作用在于自动调用:foo的to_proc方法,这么说起来可能比较抽象,那就来举个栗子吧.
比如说 想让[2,3,3,3,3]
这个数组里的每个数字都加1
我们有好几种做法
第一种
[2,3,3,3,3].map do |i| i.next end
这种写法可以说是最常见也最容易理解的.
第二种
aproc=proc{|i| i.next} [2,3,3,3,3].map(&aproc) #这里的&表示传进来的这个aproc是个proc或者说block..
这里等于说是把第一种方式里的block给单独拿出来变成一个proc再以参数的形式传给数组的map方法.
第三种
aproc=:next.to_proc [2,3,3,3,3].map(&aproc)
从这里起事情开始变得有趣了起来w..to_proc是一个预先定义在Symbol类中的方法.
这里是它的实现
class Symbol def to_proc Proc.new do |obj, *args| obj.send self, *args end end end
foo调用to_proc方法后返回了一个proc{|i| i.foo}
第四种
aproc=:next [2,3,3,3,3].map(&aproc)
诶诶诶?为什么这里可以直接把一个Symbol像Proc一样传进去啊.
这是因为&
这个神奇的符号,它会自动调用跟在它后面的Symbol的to_proc方法
第五种
[2,3,3,3,3].map(&:next)
啊咧..这好像就是我们在文章开头中提到的那种写法
拓展:这里还有一个小细节需要注意(其实窝在上面提到过,不过感觉没讲清楚这里单独拿出来再讲讲)
如果&
号后面接的是个Symbol才会自动调用它的to_proc方法.
如果&
后面跟着的东西已经是个proc了那么直接把proc作为参数传给前面的函数
也就是说[2,3,3,3,3].map(&:next)和[2,3,3,3,3].map(&:next.to_proc)其实是一样的
如果能帮到你,不胜荣幸.
参考资料: