lazybios

《Ruby 元编程》读书笔记 (十六)

Ruby元编程

Self Yield

给一个方法传入代码块时,可以通过yield占位对块进行回调。除了直接调用块外,还可以通过yeild给代码块传递参数,这个self yield的惯用法,其实就是通过yield self,把自身(当前对象)传递给代码块。

使用tap调试方法调用链

[a,b,c].push(d).shift.tap {|x| puts x}.upcase.next
#输出
a

这里的tap方法就是利用了self yield技术,将自己传给代码块,从而让我们能打印出当前的状态值,辅助调试方法调用链,避免“火车失事”问题。

Kernel#tap的定义和文档描述如下:

tap{|x|...}  obj

Yields self to the block, and then returns self.** The primary purpose of this method is to “tap into” a method chain, in order to perform operations on intermediate results within the chain.**

不过自己实现一个tap方法也不难:

class Object
    def tap
        yield self
        self
    end
end

Symbol#to_proc方法

Symbol#to_proc方法的目的是位了用更简单的方式来替代一次调用代码块。所谓的一次调用代码块是指那些只有一个参数,且对这个参数只调用一个方法。如下:

names = [bob, bill, heather]
names.map{ | name | name.capitalize } #=> [“Bob”, “Bill”, “Heather”]

那么Symbol#to_proc方法又是怎么做到精简的呢?继续往下看

names = [bob, bill, heather]
names.map(&:capitalize) #=> [“Bob”, “Bill”, “Heather”]

上面出现了&符号,&符号的含义是: 这是一个Proc对象,我想把它当成代码块来使用。去掉&符号,将能再次得到一个Proc对象。&符号可以用作任何对象,它会调用该对象的to_proc方法来把这个对象转换为一个Proc,之后map方法会将names数组中的每个值作为这个Proc对象的参数进行调用。

class Symbol
    def to_proc
        Proc.new { |x| x.send(self) }
    end
end

用到了动态派发,to_proc方法会返回一个Proc对象,该对象会在传入的参数上执行:method_name(符号方法,因为动态调用的是self,符号对象本身)。

此外,Ruby中的对象还支持多于一个参数的块,类似inject方法(ps: 这里还不是很熟),见下面代码。

[1,2,5].inject(0) { | memo, obj | memo + obj } #=> 8
[1,2,5].inject(0, &:+) #=> 8

-完-

微信关注「日拱一卒」公众号