[Ruby] block, Proc 和 Lambda
keywords: block
, yield
, Proc
, lambda
在 Ruby 裡,幾乎什麼東西都是物件,但其實還是有少數的例外,Block 就不是物件。也因此 Block 沒有辦法單獨的存在,也沒辦法把它指定給某個變數,像這樣的寫法都會造成語法錯誤(Syntax Error):
{ puts "Hello, Ruby" } # 這樣會產生語法錯誤
action = { puts "Hello, Ruby" } # 這樣也會產生語法錯誤
Block
建立 Block
# 第一種方式,用 do...end,通常用在多行的 block
do |token|
# ...blockCode...
end
# 第二種方式,直接用 { |token| } 表示,通常用在單行的 block
{ |token| ... }
在 methods 中執行 block
如果想要讓附掛在 methods 後的 Block 執行,可使用 yield
方法,暫時把控制權交棒給 Block,等 Block 執行結束後再把控制權交回來:
# 透過 yield 掛上 block
def say_hello
puts "開始"
yield # 把控制權暫時讓給附掛在 say_hello 後的 Block
puts "結束"
end
say_hello {
puts "這裡是 Block"
}
=begin
"開始"
"這裡是 Block"
"結束"
=end
使用 pipe 在 block 中代入參數(token)
Block 本質上是匿名函式,我們也可以在 Block 中代入參數,而 Block 中的 │ (pipe)就是這個匿名函式的參數,稱做 token
,token 是在這個 Block 裡專屬的區域變數,Block 執行結束後就會失效了:
# pipe 中的變數是區域變數,離開 block 就找不到
5.times do |i|
puts i # 這個變數 i 只有在 Block 裡有效
end
puts i # NameError,離開 Block 之後就失效
其他使用 pipe 代入 token 的例子:
# 使用 pipe 的例子 1
def say_hello
puts "開始"
yield 123 # 把控制權暫時讓給 Block, 並且傳數字 123 給 Block
puts "結束"
end
say_hello do | x | # 這個 x 是來自 yield 方法,把 123 代入 |x|
puts "這裡是 Block,我收到了 #{x}"
end
# 使用 pipe 的例子 2
def this_method_takes_a_block
yield(5)
end
this_method_takes_a_block do |num| # 把 5 代入 |num|
puts num # 回傳 5
end
# 使用 pipe 的例子 3
def this_silly_method_too(num)
yield(num + 5)
end
this_silly_method_too(3) do |wtf| # 把 3 + 5 代入 |wtf|
puts wtf + 1 # 回傳 9
end