iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 8
1
自我挑戰組

關於 Ruby on Rails 的那些事系列 第 8

Day 8 - 程式碼區塊 Block 「Lambda」 and 「Proc」

  • 分享至 

  • twitterImage
  •  

Ruby 世界幾乎都是物件

先來簡單說明一下什麼是物件:

物件(object) = 狀態(state) + 行為(behavior)

以我家的狗狗為例,她叫「蒟蒻」,是個女生,品種為台灣犬,有烏黑的毛髮,這些是物件的狀態,而行為呢,就是走會路、吃東西、吠叫等,兩個條件都達到了,所以可以說狗狗是一個物件。以此類推,人、昆蟲、甚至是病毒,許多東西都是物件,具有狀態及行為。

非物件的 Block

言下之意就是說也有非物件的東西,其中一個例外就是今天要介紹的主角 block。因為不是物件,所以 block 無法單獨存在於 Ruby 世界。
講了這麼多,到底 block 長什麼樣子呢,首先來看兩段程式碼:

[1..10].map{ |x| x + 1 }

以及

[1,3,5,7,9].each do |y|
  puts y * 2
end

這兩個方法後面都寫了一串東西,這東西就是 block,分別是do...end{...},正常情況下你不會看到 block 單獨飄在程式碼中 (如果你看到了,表示那個人寫錯了) 。在 block 前面一定會有個 method,就像寄生蟲需要依附在宿主身上,而且 block 能不能被執行,也要看 method 的臉色,只有 method 裡執行 yield 的時候,才會把控制權交給 block,拿到控制權的 block 才可以執行程式,當跑完 block 的程式後,在把控制權交回給 method 繼續跑接下來的程式。

def test
  puts "你現在在 method"
  yield
  puts "你已回到 method"
  yield
end
test {puts "你目前在 block"}  #把 block 掛在 test 方法後面

# 執行結果
# 你現在在 method
# 你目前在 block
# 你已回到 method
# 你目前在 block

將 block 物件化

Proc

Proc 是一個類別,用這個類別的new方法產出一個實體,並且 assign 給一個變數儲存起來,方便後續重複使用:

this_is_a_dog = Proc.new { |name| puts "The dog's name is #{name}." }

當要執行這個變數時,有六種方式可以執行,這邊就簡單使用call方法:

this_is_a_dog.call("Jill")

# 執行結果 The dog's name is Jill.

Lambda

概念與 Proc 類似,雖然寫法不同,但呼叫方法也一樣是用call
第一種寫法:

add_one = lambda { |y| puts y + 1 }
add_one.call(1)

# 執行結果 2

第二種寫法:

add_two = -> (n) { puts n + 2}
add_two.call(1)

# 執行結果 3

Proc 與 Lambda 不同之處

定義時設定的參數呼叫時帶入的引數 數量不同時:

  • Proc 不檢查引數數量,將正常執行程式
double = Proc.new { |y| puts y * 2 }
double.call(1,2,3)

# 執行結果 2

  • Lambda 會檢查引數數量,若數量不對則噴出錯誤訊息
triple = lambda { |t| t * 3 }
triple.call(1,2,3)

wrong number of arguments (given 3, expected 1) (ArgumentError)

同場加映:「&」是怎麼回事?

當初我在學習這個章節的時候是滿頭問號,完全不懂這個是怎麼回事,現在看程式碼已經可以理解這東西在做什麼了!
「&」可以說是把 block 轉換成 Proc,先給你看一段程式碼

def say_hi(&block)
	puts block.call
end

say_hi { 'hello, world' }

# 執行結果 hello, world

第1行定義了say_hi方法,後面可接受一個參數。在第5行呼叫這方法,但後面接了一個 block,還記得 block 的特性是不會主動執行嗎?接著 block 被丟進第1行裡的括號中,而 block 本身不能當參數,這時候就要出動&,透過 & 可以把 block 變成 Proc,這樣就可以在第2行的時候使用call方法執行裡面的程式片段。
這段可以搭配前面的 yield 一起看,這樣可能比較好理解 (吧)

學無止盡,每天都要進步一點點!

[Ruby] 如何理解 Ruby Block
[Ruby] 程式碼區塊(block), Proc 和 Lambda
為你自己學Ruby on Rails-高見龍
Proc是甚麼可以吃嗎


上一篇
Day 7 - 想要會飛就得當小鳥的孩子嗎?
下一篇
Day 9 - 淺談 REST and RESTful
系列文
關於 Ruby on Rails 的那些事30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言