Try   HackMD

Ruby 區塊 Block

tags: Ruby

Block 簡介

Block = 一段不會被主動執行的程式碼

5.times do |i| puts i end p (1..100).select { |n| n.odd? } 1.upto(10) { |n| puts n }

do .. end{ } 兩種寫法

# do .. end 5.times do |i| puts i end # 大括號式的寫法 5.times { |i| puts i }

Block 沒辦法單獨存活

# 語法錯誤 { puts "我是大括號型的 Block" } # 語法錯誤 do puts "我是 do end 型的 Block" end

Block 的性格其實有些扭曲

Block 就像寄生蟲一樣依附在方法後面
Block 會不會執行,要看宿主臉色

def say_hello puts "Hello, 你好" end say_hello { puts "here!" } puts "there!"

yield = 把控制權轉讓給 Block

def say_hello puts "Hello, 你好" yield puts "Hello, 大家好" end say_hello { puts "here!" } puts "there!"

控制權轉讓的時候

轉讓的同時,還可以帶上拌手禮

def say_hello yield 3, 8 end say_hello do |n, m| puts n puts m end

Block 完成的時候也會帶東西回來..

def test_two if yield(3) puts "yes, it is 2" else puts "no, it is not 2" end end test_two { |n| n == 2 # 自動回傳 Block 的最後一行執行結果 }

練習

# 請試著完成自己土砲陣列的 select 方法: # # def my_select(list) # # 實作內容 # end # p my_select([1, 2, 3, 4, 5]) { |i| i.odd? } def my_select(list) result = [] list.each do |item| result << item if yield(item) end result end p my_select([1, 2, 3, 4, 5]) { |i| i.odd? }

Block 其實不是參數

怎麼知道 Block 是否存在?

def say_hello if block_given? # 檢查 Block 是否存在 yield end end say_hello

不同的 Block 寫法差異

結合率強度

list = [1, 2, 3, 4, 5] p list.map { |item| item * 2 } # 大括號結合率強 # 印出 [2, 4, 6, 8, 10] p list.map do |item| item * 2 end # do...end 結合率弱 # 印出 <Enumerator: [1, 2, 3, 4, 5]:map>

物件化的 Block

雖然 Block 沒辦法單獨存活,但被物件化之後就可以了

Proc

add_two = Proc.new { |n| n + 2 } p add_two.call(3) # 印出 5

呼叫 Proc 的方法

p add_two.call(3) p add_two[3] p add_two.(3) p add_two.===(3)

Lambda

add_two = lambda { |n| n + 2 } add_two = -> (n) { n + 2 }
class Book < ApplicationRecord scope cheap, -> { where("price <= 100") } # lambda end

Proc 與 Lambda

add_two_proc = Proc.new { |n| n + 2 } add_two_lambda = lambda { |n| n + 2 } p add_two_proc.call(1, 2, 3) # 正常執行,印出 3 p add_two_lambda.call(1, 2, 3) # 發生引數個數錯誤