Ruby Block 理解

derekzhan發表於2010-06-20

ruby中的block是比較難理解的一個概念,但是如果你懂得了什麼是回撥函式。那麼其實block的作用和回撥函式是一樣的。
我們先看一個沒帶引數的例子:
def say
yield 
yield
end
我們先看單行的block。
say{puts("hello world")}
輸出的結果為:
hello world
hello world

block就象是一個沒有名稱的函式,執行到yield就呼叫block中的程式碼執行。

如果block是多行的,那麼就應該是這樣:
say do 
puts("hello world")
puts("ni hao");
end

輸出結果:
hello world
ni hao
hello world
ni hao
每一個yield就是執行完block中所有的程式碼。


接下去我們看看帶有引數的block。
def add
puts(yield(1,2))
puts(yield(5,6))
end
add{|a,b| a+b}
輸出的結果:
3
11

block中的a,b就是這個block的引數,yield(1,3)就是呼叫這個block,並把1,3賦給a和b。

 

 

Ruby中方法和塊的關係就是一對協同例程,互相轉換程式的控制執行權,當方法中遇到yield語句,就轉到塊裡執行,塊執行完畢後,將返回到方法體中,繼續執行方法yield語句後面的程式碼。yield可以帶引數到塊中,塊也是有返回值,返回到方法體中。

方法和塊的一個作用,就是實現了操作和處理的分離,比如:File.open {...},File.open負責開啟檔案(即是操作),然後呢,如何處理呢,交給了塊。Ruby創立者這種思想,深刻地理解了,如何更貼近自然的語 言,更加深入的物件導向,更加的靈活(比如Array.each方法,只是負責取出陣列中的每個元素,具體要幹什麼,塊可以自由的設定)。

方法可以通過 if 語句加上 block_given? 條件,來判斷方法在執行的時候,是否有塊在後面,如果有,就執行if語句,再根據yield呼叫塊,如果後面沒有塊,就繼續執行if後面的程式碼。

塊只是接過方法交過來的執行權,繼續執行塊的程式碼,它不是一個結構,不是迴圈。

下面是個例子,File.open方法後跟塊的時候,可以在結束塊時,自動關閉檔案,完善了File.new方法。

 

class File 
 def File.open(*args) #將File.new方法需要的一籃子引數放到*args陣列裡 
 r=f=File.new(*args) #將陣列*args分散開並傳給File.new ,為什麼這裡要把控制程式碼給兩個值? 
if block_given? #block_given?方法屬於Kernel模組,而此模組包含在Object中, 
begin #定義一個begin結構,以便即使有錯誤,也可以執行ensure語句 
r=yiled f # f傳遞到塊中,r接受了塊的返回值。 
ensure 
f.close #不管有沒有錯誤,都會在退出塊時,關閉檔案,關閉檔案, 
end #可以確保快取的東西都寫入檔案,並且可以交出佔用的資源。 
end 
return r #如果不存在塊,直接返回r 
end 
end 

  

相關文章