在Ruby的一切都是一個對象。甚至一個代碼塊也是一個對象!在Ruby中,代碼對象被稱為代碼塊。你可以把代碼塊想像成小的程序單元。它們包含Ruby代碼並且能夠在執行它們時轉入到方法中。在Python,C和Java中與之類似的概念是函數指針,匿名函數,內部類和回調函數。
Ruby代碼塊的語法是,把Ruby代碼放在大括號之間或放在do/end命令之間。如下所示:
{
#這是一個代碼塊...
}
do
#...並且這也是一個代碼塊
end
在一個很簡單的實例中,{puts"hello world"}就是一個有效的代碼塊。那麼,你應該如何使用這些代碼塊並且把它們作為一組代碼傳遞給一個方法呢?為此,首先要定義一個如下形式的簡單方法:
def someMethod
yield
end
命令yield把控制傳遞給代碼塊(它被傳遞給這個方法)。下面的代碼向你展示,一個代碼塊是如何被傳遞到上面這個方法的。
irb(main):001:0> someMethod {puts "hello world"}
hello world
每當調用yield時,執行傳遞到該方法的代碼塊。下面是另一個更復雜些的方法的例子,它使用了一個代碼塊來做更多的工作。
irb(main):001:0>
def fibonacci (stop)
while stop < 20
stop=yield
end
end
=> nil
irb(main):006:0>
i=0; j=1; fibonacci(j) {puts i; temp = i; i = j;j = temp + j}
0
1
1
2
3
5
8
代碼塊被應用於整個Ruby中。最重要的是,代碼塊被Ruby內部地應用於象Array,Hash,甚至String這樣一些類的iterator方法中。一個代碼塊其實就是,你定義要執行什麼任務(典型地,是針對一個元素的任務)。為了進一步說明代碼塊和iterator的使用,我們提供了一個小例子。假定你定義了一些場院動物類(如圖3所示),還有一個這些動物的數組,你可以通過在這個數組上使用一個代碼塊和一個迭代子來實現讓每一種動物發聲。
圖3.簡單的場院動物類
irb(main):031:0>
barnYard = [Cow.new, DUCk.new, Chicken.new, Horse.new, Dog.new]
=> [#<Cow:0x58d2f48>, #<Duck:0x58d2f30>, #<Chicken:0x58d2f00>, #<Horse:0x58d2ee8>, #<Dog:0x58d2ed0>]
irb(main):032:0>
barnYard.each {animal animal.talk}
Mooooo
Quack
Cluck-cluck
Naaaay
Bark bark
在barnYard上調用的每個方法正是一個數組上的iterator方法之一。注重,符號用於定義要接收的參考。在本例情況中,代碼塊接收一個參數;也就是把barnYard中的每一種動物作為迭代子來遍歷這個動物集合。
迭代子和代碼塊甚至答應我們完成如下一些相當簡單和整潔的事情:
irb(main):001:0>
3.times {puts "Ruby is cool!"}
Ruby is cool!
Ruby is cool!
Ruby is cool!
是的,即使是Integer類也提供了一個迭代子(times方法)-它使用一個代碼塊來快速地執行循環操作。
在離開有關代碼塊和迭代子的討論前,你還應該知道代碼塊可以被賦值給一個變量。事實上,這樣的代碼塊實際上是Proc類的實例。你可以使用new方法來定義一個Proc實例,或者使用這些Proc實例-這些實例稍後可以使用call方法來調用。
irb(main):003:0> simpleProc.call
hello
=> nil
irb(main):004:0> anotherProc.call("hello yourself")
hello yourself
=> nil
這答應一個可重用的代碼塊可以被包裝為一個對象(它可以在任何地方執行)而進行傳遞。下面是顯示Ruby中可重用代碼的示例!
irb(main):001:0>
def simpleMethod(aProc)
puts "Is Ruby cool or what?"
aProc.call("Way cool dude!")
end
=> nil
irb(main):005:0>
simpleMethod(anotherProc)
Ruby酷不酷?相當不錯!