代码块,我的理解就是匿名方法,有点像Java中的匿名类一样,似乎用更贴切的说法叫闭包,一个我至今未接触过的东西。学习到代码块和代码块对象(Proc)的时候,看着很晕,一个代码块对象可以用lambda和->同时定义,与对代码块的错误理解纠结在一起,晕了一晚上。今天早上又找了些资料看看,最终才弄懂。写这篇文章的时候,使用的Ruby是1.9.2
Block和Proc的区别就是Proc是Block Object,需要用call方法调用,而Block则不用。
1. 代码块的定义分为两种方式调用,一种是do end定义,适用于多行代码,一种是{}定义,适用于一行,两者没有优劣,只有习惯的不同,遵从这种文化吧。
下面这个就是最简单的代码块示例:
5.times do |i| puts "No.#{i+1}" end
但是,如果你想在一个方法调用一个外部的代码块,如何做到呢?这个magic可以通过yield关键字来做到
def bye(name) puts "bye,#{name}" if block_given? yield end end bye("Steve Jobs"){puts "missing you "}
代码块可以作为一个隐含参数,并且是最后一个,而且只能使用一个,来传递给别的方法,前面正常的参数要用括号起。像这个例子,我传递了一个打印“missing you”的代码块给方法bye,通过block_given?来判断是否传递了一个代码块过来,传过来的话,则用yield执行,如果不判断,而直接使用yield的时候,没传代码块是要报错的。其输出结果为:
bye,Steve Jobs
missing you
2.Proc的使用
Proc就是代码块对象,既然是对象,一旦定义,就可以多次使用了,Proc当然可以用new来创建,这个似乎并不常用,常用的倒是用lambda方法和符号->来定义
2.1 lambda方式
在方法名lambda后面加上代码块即可,示例如下:
proc=lambda {|name| puts "hello,#{name}"} proc.call 'theoffspring' proc.call 'Mike'
输出结果是:
hello,theoffspring
hello,Mike
而且,作为对象,它可以作用参数传递给方法调用,个数不限,位置不限,这点克服了代码块来作为参数传递的局限性,如:
def test_proc_multi_params(name, proc, proc2) puts "#{name} is coming ,and he wants to..." proc.call proc2.call end test_proc_multi_params("the offspring", lambda { puts "eat potato" }, lambda { puts "and water melon" })
输出结果:
the offspring is coming ,and he wants to...
eat potato
and water melon
不过 ,代码块可以通过在参数名前加个&来转换成代码块对象,但仍然只能有一个,且在方法参数列表的最后,如:
def test_converted_block(name,&action) puts "#{name} is " action.call end test_converted_block("the offspring") {puts "eating lunch"}
输出:
the offspring is
eating lunch
注意调用 test_converted_block的参数写法,挺特殊的,不得不承认
2.2 ->方式
你只要把lambda出现的地方换成->就行了,哦,对了,这种方式在定义Proc参数的时候,要写到括号的外面,多个的话,以逗号分隔。
如:
proc=-> name { puts "hello,#{name}" } proc.call 'theoffspring' proc.call 'Mike'