今天要來介紹 block
:花括號{}
和 do ... end
。
不能指定給變數:在 Ruby 中 block 不能單獨存在,也就不能賦值給其他物件。
不能當參數傳進方法:也因為不是物件,沒有所謂的值,因此不能當作參數使用。
(1..5).map {|i| i * 2 if i >= 3}
# 上下兩段程式碼會得到相同的結果
(1..5).map do |i|
i * 2 if i >= 3
end
怎麼讓 block
活起來呢?從上面的例子可以看到 block 裡通常是一段程式碼,也就是說,只要用對方法,我們就不單單能把參數傳來傳去,甚至可以把一段程式碼帶入。
所以,我們第一件要做的事就是先把 block
物件化,比較常見的有三種方法:
我們可以用 Proc.new{}
把 block
物件化,物件化後就是一個參數,再搭配 call
方法執行 block 內的程式碼:
class Office
def self_introduction(string, sentence)
puts string
puts sentence.call(18)
# 也可寫成sentence[18]
end
end
staff = Office.new
my_age = Proc.new {|age| "I'm #{age} years old"}
# 上一行也可以寫成 my_age = proc {|age| "I'm #{age} years old"}
staff.self_introduction("Hello", my_age)
# 印出 Hello
# I'm 18 years old
將 block
直接掛在方法後面,整段程式碼最會被 yield
的接住,可以想成把 block 的 {} 脱掉直接放進方法中。
class Office
def self_introduction(string)
puts string
puts yield(18)
end
end
staff = Office.new
staff.self_introduction("Hello"){ |age| "I'm #{age} years old" }
# 印出 Hello
# I'm 18 years old
也許可以想成上述方法的綜合體( proc 頭, yield 腳),如同 yield 一樣直接把 block 掛在方法後面,又能夠把 block 當做參數:
class Office
def self_introduction(string, & sentence)
puts string
puts sentence.call(18)
end
end
staff = Office.new
staff.self_introduction("Hello"){ |age| "I'm #{age} years old" }
# 印出 Hello
# I'm 18 years old
以上是三種常用的 block
物件化方法,個人認為 Proc way 的好處是按步驟把 block 物件化後指定給一個變數,對於新手學習來說很直觀,需要反覆用到那個 block
時也方便;而 yield way 則是可以讓程式碼參數最少、行數最少,更能一眼看出程式碼的用途。
至於解決方法沒有好不好,只有適不適合,下一篇我們拿一個事件觸發的題目用 &
演練看看。
此文同步刊登於CJ-Han的網站