Proc是對塊及其context(局部變數的範圍以及棧架構)進行對象化處理之後得到的過程對象。您可以像使用無名函數那樣來使用Proc,但它不會匯入局部變數的範圍(可以把動態局部變數用作Proc局部變數)。
在下例中,正因為Proc一直保持著局部變數的範圍,所以才能調用var變數。
var = 1$foo = Proc.new { var }var = 2def foo $foo.callendp foo # => 2
從產生Proc的方法中返回以後,若Proc中出現return或retry的話,會引發LocalJumpError異常。
def foo proc { return }endfoo.call# => in `call': return from proc-closure (LocalJumpError)def foo proc { retry }endfoo.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 中,再次運行eachproc = Proc.new { retry }(1..5).each(&proc)#=> retry from proc-closure (LocalJumpError)
這正是Proc對象用作調用塊時的限制。
對塊及其context進行對象化處理之後返回結果。
若沒有給出塊的話,就會把調用該方法的方法所帶的塊轉換為Proc對象並將其返回。
def foo pr = Proc.new pr.call(1,2,3)endfoo {|args| p args }# => [1, 2, 3]
Proc.new方法深入
Proc.new對塊及其context進行對象化處理之後返回結果。
若沒有給出塊的話,就會把調用該方法的方法所帶的塊轉換為Proc對象並將其返回。
def foo pr = Proc.new pr.call(1,2,3)endfoo {|args| p args }# => [1, 2, 3]這與下例相同def foo yield(1,2,3)endfoo {|args| p args }# => [1, 2, 3]
若主調方法並沒有帶塊時,則引發ArgumentError異常。
def foo Proc.newendfoo# => -:2:in `new': tried to create Proc object without a block (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.new do |year| year % 4 == 0 && year % 100 != 0 || year % 400 ==0end p leap.call(2000) #=> truep leap[2013] #=> falsep leap[2016] #=> true
將塊變數設定為 |* 數組 | 的形式後,就可以像方法參數一樣,以數組的形式接收可變數量的參數。
double = Proc.new do |*args| args.map{|i| i * 2 } # 所有元素乘兩倍end p double.call(1, 2, 3) #=> [2, 3, 4]p double[2, 3, 4] #=> [4, 6, 8]
除此以外,定義普通方法時可使用的參數形式,如預設參數、關鍵字參數等,幾乎都可以被用於塊變數的定義,並被指定給 Proc#call 方法。