msn email google-talk twitter tumblr flickr

Ruby学习笔记:关于Proc

创建方式

三种创建Proc对象的方法 比较常见的是前2种创建方法

   1      > a = lambda{puts"aaa"}
   2      => #<Proc:0x01160084@(irb):1>
   3      > a.class
   4      => Proc
   5  
   6      > b = Proc.new{puts"bbb"}
   7      => #<Proc:0x011459b4@(irb):4>
   8      > b.class
   9      => Proc
  10  
  11      > c = proc{puts"ccc"}
  12      => #<Proc:0x0113a7f8@(irb):6>
  13      > c.class
  14      => Proc

可以看到三个对象的class都是Proc

不同点:

参数检查

优先使用Proc.new 因为lambda和proc都会检查参数

p = Proc.new {|x,y| print x,y }
p.call(1) # x,y=1: 如果缺少参数就用nil代替,打印 1 和 nil
p.call(1,2) # x,y=1,2: 打印 12
p.call(1,2,3) # x,y=1,2,3: 多余的参数被忽略了: 打印 12
p.call([1,2]) # x,y=[1,2]: 数组元素自动分配个每个参数: 打印 12

l = lambda {|x,y| print x,y }
l.call(1,2) # 这样没有问题
l.call(1) # 参数个数错误
l.call(1,2,3) # 参数个数错误
l.call([1,2]) # 参数个数错误
l.call(*[1,2]) # 明确的告诉lambda这是一个数组参数,这可以正常运行。

proc的参数检查同lambda 在此略过

运行方式

通过a=Proc.new{|x| puts x}的方式定义的Proc对象在运行时更像是一个块通过y=lambda{|x| x+1}的方式定义的lambda对象运行期间表现类似于匿名方法

这两个的对象的区别在于:
Proc更像是一个块的定义
而lambda更像是一个方法的定义。

区分Proc和lambda可以在一个对象上调用lambda?方法,如果返回true就是lambda否则就是Proc

def test
puts "entering method"
p = Proc.new { puts "entering proc"; return }
p.call # 这里调用Proc.new会使得方法return
puts "exiting method" # 这行永远不会执行
end
test #Proc块更像是将代码注入到call的位置 代码中的return会导致方法中断

def test
puts "entering method"
p = lambda { puts "entering lambda"; return }
p.call # 调用lambda不会导致方法return
q = proc { puts "entering proc"; return }
q.call # 调用proc也不会导致方法return
puts "exiting method" #现在这行会执行
end
test #lambda块和proc块的执行类似匿名方法 内部的return类似于方法内部的return

相同点:

都是闭包
产生一个闭包就像是打包一件行李 任何时候打开行李 都包含打包时候放进去的东西 也就是说调用闭包的时候 它包含产生它的时候你放进去的东西
Furthermore, those variables remain in scope inside the Proc object, no matter where or when you call it.

def call_some_proc(pr)
a = "irrelevant 'a' in method scope"
puts a
pr.call
end
a = "'a' to be used in Proc block"
pr = Proc.new { puts a } #lambda及proc运行效果同Proc.new
pr.call
call_some_proc(pr)
输出:
'a' to be used in Proc block
irrelevant 'a' in method scope #puts a的输出
'a' to be used in Proc block

可以看出Proc中的a拥有自己独立的生命周期(scope) 并不与运行环境中的同名变量a产生冲突