# Ruby Block ## 特色 1. 一段不會被主動執行的程式碼 2. 無法單獨存活,被物件話後就可以 ## 寫法 do .. end 和 {} 兩種寫法 ```ruby= 5.times do |i| puts i end ``` ```ruby= 5.times { |i| puts i } ``` ## yeild ### 將控制權轉讓給Block 一般執行程式的狀態 (執行順序 #(順序)) ```ruby= def say_hello #2 puts "hi, 你好!" #3 end say_hello #1 #4 puts "there!" #5 ``` ``` hi, 你好! there! ``` Block就像寄生蟲一樣,依附在方法後的block不會直接被執行,要看宿主要不要讓你執行 以下加上block的狀況 ```ruby= def say_hello puts "hi, 你好!" end say_hello { puts "here!" #依附在方法後的block } puts "there!" ``` ``` hi, 你好! there! ``` 要讓其能被執行要靠 **yeild** 的方法 ```ruby= def say_hello #2 puts "hi, 你好!" #3 yield puts "hi, 大家好!"#5 end #1 #6 say_hello { puts "here!" #4 } puts "there!" #7 ``` ``` hi, 你好! here! hi, 大家好! there! ``` ### 轉移時附加value 控制權轉移的同時,可以附加value送出(可以不只一個) ```ruby= def say_hello yield 3, 5 #這邊的3會被引入到下方的參數n end say_hello{ |n ,m| puts n #3 puts m #5 } ``` 當完成之後會自動回傳block最後一行的執行結果,在block裡不使用return ```ruby= def test_two #2 if yield 2 #3 #5 puts "yes" #6 else puts "no" end end #1 test_two{ |n| n == 2 #4 return true } #yes ``` 應用 : 找到1~100的奇數 ```ruby= p(1..100).select {|n| n.odd?} ``` 練習 : 找出陣列中的奇數 ```ruby= def my_select(list) result = [] list.each do |n| result << n if yield(n) end result end p my_select([1,2,3,4,5]) {|i| i.odd?} p (1..100).select {|n| n.odd?} ``` ruby有倒裝的寫法 ```ruby= if x > 0 puts "hello" end ``` 可以寫成 ```ruby= puts "hello" if x > 0 ``` 的倒裝句寫法,所以: ```ruby= result << n if yield n ``` 其實等於: ```ruby= if yield n result << n end ``` ## Block 不是參數 如果沒有Block,但卻yield的話,會發生local jump error的錯誤訊息,因為yield不知道要執行哪個Block ```ruby= def say_hello yield end say_hello ``` Block不是參數,所以要知道Block存不存在要用 **block_given?** 檢查Block是否存在 ```ruby= def say_hello yield if block_given? end say_hello #沒有Block不會執行 say_hello{ puts "hi" #block_given 為 true 所以執行 "hi" } ``` :::info 不同Block 大括號 vs do ... end 的差異 ```ruby= list = [1,2,3,4,5] p list.map {|item| # {}結合率比較強,所以再執行的過程中會先執行Block item * 2 } p list.map do |item| # do ... end 結合率比較弱,所以結合率被p 搶走 item * 2 end ``` {} 的結果 [2, 4, 6, 8, 10] do .. end 的結果 #<Enumerator: [1, 2, 3, 4, 5]:map> ::: ### 物件化 Block 將 block 物件化後,透過給予引數來執行,物件化的方式有下面幾種 ```ruby= add_two = Proc.new {|n| n+2} #方法一 p add_two.call(3) #比較常用call p add_two[3] p add_two.(3) p add_two.===(3) add_two2 = lambda {|a| a + 2} #方法二 (lambda) p add_two2.call(3) add_two3 = -> (x) { x + 2 } #方法三 (lambda) p add_two3.call(3) ``` Proc vs Lambda Proc 多給引數不會發生錯誤,Lambda會發生錯誤 ```ruby= add_two = Proc.new {|n| n+2} p add_two.call(1,2,3) # 印出3 add_two2 = lambda {|a| a+2} p add_two2.call(1,2,3) #跳error ```