很久以前读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方法.这里涉及到了Ruby中闭包的概念.
第三种
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)其实是一样的
好了..在这篇文章里我们从最容易理解的使用block的方法一步一步慢慢变形成了&:foo
这种容易让人产生困扰的"缩写"形式
如果能帮到你,不胜荣幸.
参考资料: