方法和代碼塊
在Ruby中,{}或do...end之間的代碼是一個代碼塊。
代碼塊只能出現在一個方法的後邊,它緊接在方法最後一個參數的同一行上,一般由yield關鍵字調用代碼塊中的代碼。
方法是一個有名的代碼塊,是與一個或者多個對象相關聯的參數化代碼。
調用方法時必須要給出方法名、所在對象(接受者),以及零個或者多個參數值,方法中最後一個運算式的值將作為方法調用的傳回值。
代碼塊不是ruby可操作的對象,一般我們用一個Proc對象代表一個代碼塊。
有兩種方式的Proc對象,一種是proc,一種是lambda,他們都是閉包:他們會保持定義時所在範圍內的局部變數,即使在外部範圍被調用時,他們也可以對這些變數進行訪問。
方法的定義就不說了,前面有說過。
方法名以小寫字母開頭,如果方法名超過一個字母,一般用底線分割開來。
方法可選的圓括弧在許多方法調用中圓括弧是可省略的,如 puts “hello” 和 puts (“hello”)是一樣的。
ruby是一種強物件導向的語言,他的對象被完全封裝,與他們交流的唯一方式就是調用他們的方法,所以 len = "hello".length 其實是 len = “hello”.length(),只不過把圓括弧省略掉了,你看起看好像是他的屬性訪問。
一般情況下,如果參數超過一個,最好不要省略圓括弧。
代碼塊參數傳統方式就是代碼塊直接跟在方法後面,並用yield來調用代碼塊。
在函數裡面的有一條yield語句,到時候執行的時候可以執行函數外的block。而且這個block可以有自己的context, 感覺有點像callback,又有點像c裡面的宏定義。
有人說yield就充當一個預留位置的作用,函數先給一個預留位置,這個函數如同一個純需函數一樣不能直接調用,必須用block把這個位坑給添了才能使用這個函數。
def block_test(num)if block_given?#yield #無參數yield (num)elseputs numendend#block_test(1)#block_test(2) { puts "this is a block ..."}block_test(2) {|x| puts x * 2}
或者在方法的後面加上一個參數,並用&作為這個參數的首碼,這樣這個參數就會指向傳給方法的代碼塊,這個參數的值是個Proc對象,它不是通過yield調用的,而是call調用的。
def proc_test(num,&b)if block_given? #b.callb.call(num * 3)elseputs "no block"endend#proc_test(1) #proc_test(1) {puts "this is a block"}proc_test(1) {|x| puts x * 2}
建立Proc對象的3種方式Proc.new
如果在方法的最後一個形參前增加一個”&”符號,那麼Ruby會把這個形參作為一個Proc對象處理。
所有的Proc對象都有一個call的方法,當調用這個方法時,會運行建立這個Proc對象時定義的代碼塊。
如果Proc.new不帶參數,返回一個proc方式的Proc對象。Proc對象有proc方式、lambda方式。
如果Proc.new帶參數,返回一個關聯代碼塊的Proc對象,這個對象代表這個關聯的代碼塊。
p = Proc.new { puts "hello,dear..."}def proc_test(&pp)pp.callend
Kernel.lambda
lambda方法返回的是一個lambda方式的Proc對象。
lambda方法不帶參數,但是在調用時必須關聯一個代碼塊。
puts lambda{|x| x + 10}.call(2)
Kernel.proc
這個1.8是lambda的同義字,1.9是Proc.new的同義字。
這個就不說了。
代碼塊,proc,lambda的return
一個代碼塊中的return語句不僅會從調用代碼塊的迭代器中返回,還會從調用迭代器的的方法中返回。
def testputs "start.."2.times {puts "hello,";return}puts "end..." #不會別列印end
proc和代碼塊類似,所以如果在調用的proc中執行一個return語句,它會試圖從代碼塊所在的方法中返回。
而在lambda中的return語句僅僅時從lambda自身返回。
def pro_fun (msg)puts "start..."p = Proc.new {puts "hello,#{msg}";return} #會從代碼塊所在的方法pro_fun中返回p.callputs "end..."enddef lambda_fun(msg)puts "start.."lam = lambda {puts "hello,#{msg}";return} #僅僅返回自身lam.callputs "end..."enddef testputs "test start"#pro_fun "song"lambda_fun "song"puts "test end"endtest