iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 4
0
自我挑戰組

非本科之30天Ruby / Rails學習筆記系列 第 4

Day4: Block程式碼區塊及Proc, Lambda差異

  • 分享至 

  • xImage
  •  

Block in Basketball

Ruby是一個「物件導向」相當徹底的一門程式語言,幾乎所有的東西都是物件,例如:

  • 數字 Integer
  • 符號 Symbol
  • 字串 String
  • 陣列 Array
  • 雜湊 Hash

為什麼說"幾乎"呢?

Block(程式碼區塊)

在寫各種迴圈的時候,會大量的運用到Block:

numbers = [1,2,3,4,5]

p numbers.map{|num| num * 2}                #印出[2,4,6,8,10]
p numbers.select{|num| num.odd?}            #印出[1,3,5]
p numbers.reduce(0){|accu,num| accu + num } #印出15
5.times { puts "Hello" }                    #印出5次Hello

numbers.each do |num|
  num * 2                                   #印出[2,4,6,8,10]
end

在Ruby,{ ... }及do end就是Block,且前面要接一個method。

==Block並不是物件,本身不能獨立存在。==

puts {"Hello, World!"}         #會出現語法錯誤
sentences = {"Hello, World!"}  #會出現語法錯誤

讓Block獨立存在的方法: Proc , Lamda

雖然Block不是物件,但Ruby有內建兩個方法可以使Block物件化。

Proc

ninjutsu = Proc.new {puts 'らせん(螺旋)がん(丸)'}
ninjutsu.call        #印出 らせん(螺旋)がん(丸)

可以用call的方式呼叫,且可以帶參數

#call方法呼叫
calculator = Proc.new {|num| puts num * 2}
calculator.call(5)   #印出 10


#call()方法且帶參數呼叫
def sushi_plate(price)
  return Proc.new {|num| num * price}
end

nigili = sushi_plate(50)  #100
avacado = sushi_plate(30) #150

puts "Nigili is $#{nigili.call(2)} and avacado is $#{avacado.call(5)}."
#印出Nigili is $100 and avacado is $150.

==注意!!!==

Proc.new { return ... }

return請不要寫在Proc的Block裡,否則程式碼執行到這段後就會停止(return完後立即停止),不會繼續往下走。

def proc_airline
  p "strat from TPE"
    airline_proc = Proc.new { return "Eva airline" }
    airline_proc.call
  p "has arrived NRT"
end
  p proc_airline
    #印出"strat from TPE" 
    #   "Eva airline"
    
    #"has arrived NRT"不會印出,因為在第3行就停止了。

Lambda

有點類似匿名函式

#方式一:
calculator = lambda {|num| puts num * 2}
calculator.call(5) #印出 10

#方式二:
calculator = -> (n) {puts n * 2}
calculator.call(5) #印出 10

Proc與Lambda的差異

這樣比較起來,兩個東西看起來真的非常相似,但他們之間還是有一點點的差異存在,我們來看以下例子:

差異1.

若block預期有參數要帶入,Lambda的call不給參數會出現錯誤,Proc的call則不會出錯而是會回傳nil

lambda = -> (name) { puts "Hello #{name}" }
lambda.call("Ruby")  #印出 Hello Ruby



proc = Proc.new { |name| puts "Hello #{name}" }  
proc.call("Ruby")    #印出 Hello Ruby

目前看起來都很正常,但再看下面:

lambda.call()        
#出現error:wrong number of arguments (given 0, expected 1) (ArgumentError)

proc.call()     #印出 Hello 

Lambda函式若有預期要傳入參數但call卻沒有給的話,會直接跳出錯誤訊息,Proc後的call雖然也沒有給參數,程式還是可以過的,因為Proc會自動給nil

差異2.

Proc的block裡若有return,會直接終止程式不繼續往下走,Lambda則不影響,會完整跑完程式。

def proc_pikachu
  proc = Proc.new { return }
  proc.call
  p "使用鋼鐵尾巴!!"
end

proc_pikachu     # 印不出 "使用鋼鐵尾巴!!"
def lambda_pikachu
  lam = -> { return }
  lam.call
  p "使用鋼鐵尾巴!!"
end

lambda_pikachu   # 印出"使用鋼鐵尾巴!!"

The difference between procs and lambdas is how they react to a return statement. A lambda will return normally, like a regular method. But a proc will try to return from the current context.The reason is that you can’t return from the top-level context.

from rubyguides

簡單總結一下:

Block不是物件,不能獨立存在。

Proc可帶參數,要求有參數,call卻沒給參數時會回傳nil,{return...}會跳出程式。

Lambda使用起來更像我們一般使用的method,且會嚴格要求參數數目,就算{return...}也會把程式跑完。

參考資料:
rubyguides
Modules in Ruby: Part II
What are Lambdas in Ruby?
Using Lambdas in Ruby
為你自己學Ruby on Rails

“Perseverance is not a long race; it is many short races one after another.”

– Walter Elliott, Clergyman

本文同步發佈於: https://louiswuyj.tw/


上一篇
Day3: Ruby世界中的符號(Symbol)是什麼?與字串(String)有什麼差異?
下一篇
Day5: yield在method裡的角色
系列文
非本科之30天Ruby / Rails學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言