在 Ruby 世界中有著區塊(本篇將稱 block)的特殊語法,跟語言的執行程序上有大大的關聯,今天就來好好跟大家介紹這些部分吧!
前面有跟大家說到 ruby 幾乎甚麼都是物件,但唯獨 block 這個東西他不能算是物件,而
block 在 ruby 中有兩種:
- {} 之內
- do...end 的範圍內
總結有以下的特性:
- 一段不會被主動執行的程式碼
- 不是物件
- 像寄生蟲一樣需要依附在某些方法或物件,且不是參數
Block 會不會執行,要看宿主臉色,是否有 yield
可以看下面的例子,我們定義一個吃東西的方法,food 是參數,下面的兩種 block 類型其實都不會被執行,既使看起來有被呼叫到,就像我們上面說的特性,不會被主動執行,也不是參數。
def eat_something(food)
# eat something here
end
eat_something(rice) {
puts "Block在這"
}
# 或是 do ... end 寫法
eat_something("noodle") do
puts "這裡也是Block"
end
不知道大家有沒有在馬路上看過這樣的標誌?
大家應該知道這樣的號誌出現就是行車要禮讓行人的路口,等行人過去之後才能繼續前進。
其實 block 的運作就是像是這樣的情境喔!!
當出現 yield 的時候,區塊內的程式碼就會馬上被執行,而這樣的狀況其實是控制權的轉讓,當執行完成後再交出控制權回去依序執行剩下的程式碼。
舉個例子來說:
下面個別字串後面括號的順序就是執行的順序喔! 可以看到 yield 表示將控制權交給 block { } 內的程式碼
def drive_car
puts "行駛中!!(1)"
yield
puts "我是好公民要等行人過完才能走喔!!(3)"
end
drive_car {
puts "停車!--這裡是block喔--(2)"
}
puts "可以走啦!!(4)"
Block 不是參數,但可以做為傳遞參數的角色。
轉讓的同時,還可以帶上拌手禮傳遞參數,依照傳遞的多寡可以依序轉讓。
def block_pass_one
yield 10 # 傳遞10出去
end
block_pass_one do |n| # do..end 之間接到參數並指定給 n
puts n # 印出 10
end
def block_pass_two
yield 10,20 # 傳遞10, 20出去
end
block_pass_two do |n, m| # do..end 之間接到參數並依序指定給 n, m
puts n # 印出 10
puts m # 印出 20
end
會出錯喔!! 控制權轉讓之後沒有 block 可以接的話就會有 localJumpError。
def say_hello # 轉讓控制權,往下找到 test two 的方法
yield
end
say_hello # no block given (yield) (LocalJumpError)
Block,不用寫 return,最後一行的執行結果會自動變成回傳值。像是一些方法的使用可以看出來,如下面這些例子
# map 與 select 方法 {} 之間的運算就是最後的回傳。
p (1..10).map{|x|x*2}
p (1..10).select{|x|x.odd?}
# test two 方法後面接上block,{}內的判斷就成為最後的回傳
# yield後面帶入的參數會影響下方{}內判斷結果,再回到原本方法去判斷是要印出哪個內容
def test_two
if yield(2)
puts "yes, it is 2"
else
puts "no, it is not 2"
end
end
test_two {|n| n == 2 }
也會出現 localjumperror,因為 Block 不是一個方法,不知道 Return 到哪裡去,所以造成錯誤。
p (1..100).select{ |x| return x % 2 == 0 }
一般來說是一樣的,但可能會有優先度的差別,在一些方法的寫法上導致類似先乘除後加減的狀況。
p [*1..10].map { |i| i * 2 }
# => 得到 [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] {} 優先度高
p [*1..10].map do |i| i * 2 end
# => 得到 <Enumerator: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]:map> do...end 優先度低,
# 可以還原成 (p [*1..10].map) do |i| i * 2 end,括號內先執行完,所以後面的條件沒有被帶入執行。
以上就是基本對於 block 相關的介紹,後面可以開始進入 ruby 這充滿物件的世界中-物件導向,了解一下關於物件導向的一些概念吧。
參考資料: