Ruby 的 pretzel colon

很久以前读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这种容易让人产生困扰的"缩写"形式

如果能帮到你,不胜荣幸.

参考资料:

点击右边的按钮加载评论,如果无法加载那估计是被墙啦..你看着办w