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方法.

第三种

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)其实是一样的


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

参考资料: