Ruby中的Proc类及Proc的类方法Proc.new的使用解析
Proc是对块及其context(局部变量的作用域以及栈框架)进行对象化处理之后得到的过程对象。您可以像使用无名函数那样来使用Proc,但它不会导入局部变量的作用域(可以把动态局部变量用作Proc局部变量)。
在下例中,正因为Proc一直保持着局部变量的作用域,所以才能调用var变量。
var=1 $foo=Proc.new{var} var=2 deffoo $foo.call end pfoo#=>2
从生成Proc的方法中返回以后,若Proc中出现return或retry的话,会引发LocalJumpError异常。
deffoo proc{return} end foo.call #=>in`call':returnfromproc-closure(LocalJumpError) deffoo proc{retry} end foo.call #=>in`call':retryfromproc-closure(LocalJumpError)
若在Proc前面加上"&"并将其传给一个带块的方法时,其运作情形类似于调用块。但从严格意义上讲,其间还存在以下不同。
#没问题 (1..5).each{break} #在ruby1.6.7,1.8中没问题。在1.6.8中则发生异常 proc=Proc.new{break} (1..5).each(&proc) #在ruby1.6中是LocalJumpError #在ruby1.8中,再次运行each proc=Proc.new{retry} (1..5).each(&proc) #=>retryfromproc-closure(LocalJumpError)
这正是Proc对象用作调用块时的限制。
Proc.new Proc.new{...}
对块及其context进行对象化处理之后返回结果。
若没有给出块的话,就会把调用该方法的方法所带的块转换为Proc对象并将其返回。
deffoo pr=Proc.new pr.call(1,2,3) end foo{|args|pargs} #=>[1,2,3]
Proc.new方法深入
Proc.new对块及其context进行对象化处理之后返回结果。
若没有给出块的话,就会把调用该方法的方法所带的块转换为Proc对象并将其返回。
deffoo pr=Proc.new pr.call(1,2,3) end foo{|args|pargs} #=>[1,2,3] 这与下例相同 deffoo yield(1,2,3) end foo{|args|pargs} #=>[1,2,3]
若主调方法并没有带块时,则引发ArgumentError异常。
deffoo Proc.new end foo #=>-:2:in`new':triedtocreateProcobjectwithoutablock(ArgumentError) from-:2:in`foo' from-:4
在使用Proc.new时,若定义了Proc#initialize方法的话,就在对象初始化时调用该方法。除此以外,它和proc是相同的。
利用Proc.new方法,或者对proc方法指定块,都可以创建代表块的Proc对象。
通过调用Proc#call方法执行块。调用Proc#call方法时的参数会作为块变量,块中最后一个表达式的值则为Proc#call的返回值。Proc#call还有一个名称叫Proc#[]。
#判断西历的年是否为闰年的处理 leap=Proc.newdo|year| year%4==0&&year%100!=0||year%400==0 end pleap.call(2000)#=>true pleap[2013]#=>false pleap[2016]#=>true
将块变量设置为|*数组|的形式后,就可以像方法参数一样,以数组的形式接收可变数量的参数。
double=Proc.newdo|*args| args.map{|i|i*2}#所有元素乘两倍 end pdouble.call(1,2,3)#=>[2,3,4] pdouble[2,3,4]#=>[4,6,8]
除此以外,定义普通方法时可使用的参数形式,如默认参数、关键字参数等,几乎都可以被用于块变量的定义,并被指定给Proc#call方法。