Proc

Proc是对块及其context(局部变量的作用域以及栈框架)进行对象化处理之后得到的过程对象。您可以像使用无名函数那样来使用Proc,但它不会导入局部变量的作用域(可以把动态局部变量用作Proc局部变量)。

在下例中,正因为Proc一直保持着局部变量的作用域,所以才能调用var变量。

var = 1
$foo = Proc.new { var }
var = 2

def foo
  $foo.call
end

p foo       # => 2

从生成Proc的方法中返回以后,若Proc中出现returnretry的话,会引发LocalJumpError异常。

def foo
  proc { return }
end

foo.call
# => in `call': return from proc-closure (LocalJumpError)

def foo
  proc { retry }
end

foo.call
# => in `call': retry from proc-closure (LocalJumpError)

若在Proc前面加上"&"并将其传给一个带块的方法时,其运作情形类似于调用块。但从严格意义上讲,其间还存在以下不同。

# 没问题
(1..5).each { break }

# 在ruby 1.6.7, 1.8中没问题。在1.6.8中则发生异常
proc = Proc.new { break }
(1..5).each(&proc)

# 在ruby 1.6 中是 LocalJumpError
# 在ruby 1.8 中,再次运行each
proc = Proc.new { retry }
(1..5).each(&proc)
#=> retry from proc-closure (LocalJumpError)

这正是Proc对象用作调用块时的限制。

超类:

类方法:

Proc.new
Proc.new { ... }

对块及其context进行对象化处理之后返回结果。

若没有给出块的话,就会把调用该方法的方法所带的块转换为Proc对象并将其返回。

def foo
   pr = Proc.new
   pr.call(1,2,3)
end
foo {|args| p args }
# => [1, 2, 3]

这与下例相同(准确地说,两者间对于参数的解释方法不尽相同。请参考Proc#yield)。

def foo
  yield(1,2,3)
end
foo {|args| p args }
# => [1, 2, 3]

若主调方法并没有带块时,则引发ArgumentError异常。

def foo
  Proc.new
end
foo
# => -:2:in `new': tried to create Proc object without a block (ArgumentError)
          from -:2:in `foo'
          from -:4

在使用Proc.new时,若定义了Proc#initialize方法的话,就在对象初始化时调用该方法。除此以外,它和proc是相同的。

方法:

self[arg ...]
call(arg ... )

执行过程对象并返回其结果。参数会被原封不动地(遵守多重赋值的原则)赋值给块的参数。

arity

返回Proc对象的参数个数。若self可接受的参数不定时,则返回

-(必要的最小值+1)
binding ((<ruby 1.7 特性>))

Binding对象的形式返回Proc对象所保有的context。

to_proc ((<ruby 1.7 特性>))

返回self

to_s ((<ruby 1.7 特性>))

返回self的字符串形式。若可能的话,还将包括生成self的源文件名、行号信息。

p Proc.new {

  true
}.to_s

=> "#<Proc:0x0x401a880c@-:3>"
yield(arg ... )

ruby 1.7 特性

Proc#call相同,但它不会检查参数的个数。

pr = Proc.new {|a,b,c| p [a,b,c]}
pr.yield(1)        #=> [1, nil, nil]
pr.yield(1,2,3,4)  #=> [1, 2, 3]
pr.call(1)         #=> wrong # of arguments (4 for 3) (ArgumentError)

它的运作等同于yield

def foo
  yield(1)
end
foo {|a,b,c| p [a,b,c]}